use ast::{Attribute, AttributeList};
use itertools::Itertools;
use local_impl::local_impl;
use spade_ast as ast;
use spade_common::location_info::{Loc, WithLocation};
use spade_diagnostics::Diagnostic;
use spade_hir as hir;
use crate::error::Result;
#[local_impl]
impl AttributeListExt for AttributeList {
fn consume_no_mangle(&mut self) -> Option<Loc<()>> {
let mut mangle_attribute = None;
self.0.retain(|attr| match attr.inner {
Attribute::NoMangle { .. } => {
mangle_attribute = Some(attr.loc());
false
}
_ => true,
});
mangle_attribute
}
fn consume_translator(&mut self) -> Option<String> {
let mut translator_name = None;
self.0.retain(|attr| match &attr.inner {
Attribute::SurferTranslator(name) => {
translator_name = Some(name.clone());
false
}
_ => true,
});
translator_name
}
fn report_unused(&self, on: &str) -> Result<()> {
if let Some(attr) = self.0.first() {
Err(attr.report_unused(on))
} else {
Ok(())
}
}
fn lower(
&self,
handler: &mut impl FnMut(&Loc<ast::Attribute>) -> Result<Option<hir::Attribute>>,
) -> Result<hir::AttributeList> {
let inner = self
.0
.iter()
.map(|attr| {
let loc = attr.loc();
Ok(handler(attr)?.map(|o| o.at_loc(&loc)))
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.flatten()
.collect();
Ok(hir::AttributeList(inner))
}
fn merge_docs(&self) -> String {
self.0
.iter()
.filter_map(|attr| {
if let Attribute::Documentation { content } = &attr.inner {
Some(content)
} else {
None
}
})
.join("\n")
}
}
#[local_impl]
impl LocAttributeExt for Loc<ast::Attribute> {
fn report_unused(&self, on: &str) -> Diagnostic {
Diagnostic::error(
self,
format!("{} is not a valid attribute for {on}", self.name()),
)
.primary_label(format!("Unsupported attribute for {on}"))
}
}