forked from libre-chip/fayalite
support #[hdl] on functions -- enables #[hdl] usage in function body
This commit is contained in:
parent
a8c804ef4a
commit
ff94dda922
9 changed files with 341 additions and 156 deletions
|
@ -9,7 +9,8 @@ use syn::{
|
|||
parse::{Parse, ParseStream, Parser},
|
||||
parse_quote,
|
||||
punctuated::Pair,
|
||||
AttrStyle, Attribute, Error, Item, Token,
|
||||
spanned::Spanned,
|
||||
AttrStyle, Attribute, Error, Item, ItemFn, Token,
|
||||
};
|
||||
|
||||
mod fold;
|
||||
|
@ -17,8 +18,20 @@ mod hdl_bundle;
|
|||
mod hdl_enum;
|
||||
mod hdl_type_common;
|
||||
mod module;
|
||||
//mod value_derive_common;
|
||||
//mod value_derive_struct;
|
||||
|
||||
pub(crate) trait CustomToken:
|
||||
Copy
|
||||
+ Spanned
|
||||
+ ToTokens
|
||||
+ std::fmt::Debug
|
||||
+ Eq
|
||||
+ std::hash::Hash
|
||||
+ Default
|
||||
+ quote::IdentFragment
|
||||
+ Parse
|
||||
{
|
||||
const IDENT_STR: &'static str;
|
||||
}
|
||||
|
||||
mod kw {
|
||||
pub(crate) use syn::token::Extern as extern_;
|
||||
|
@ -38,6 +51,10 @@ mod kw {
|
|||
}
|
||||
|
||||
crate::fold::no_op_fold!($kw);
|
||||
|
||||
impl crate::CustomToken for $kw {
|
||||
const IDENT_STR: &'static str = stringify!($kw);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -46,6 +63,7 @@ mod kw {
|
|||
custom_keyword!(custom_bounds);
|
||||
custom_keyword!(flip);
|
||||
custom_keyword!(hdl);
|
||||
custom_keyword!(hdl_module);
|
||||
custom_keyword!(input);
|
||||
custom_keyword!(instance);
|
||||
custom_keyword!(m);
|
||||
|
@ -68,34 +86,34 @@ mod kw {
|
|||
type Pound = Token![#]; // work around https://github.com/rust-lang/rust/issues/50676
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct HdlAttr<T> {
|
||||
pub(crate) struct HdlAttr<T, KW> {
|
||||
pub(crate) pound_token: Pound,
|
||||
pub(crate) style: AttrStyle,
|
||||
pub(crate) bracket_token: syn::token::Bracket,
|
||||
pub(crate) hdl: kw::hdl,
|
||||
pub(crate) kw: KW,
|
||||
pub(crate) paren_token: Option<syn::token::Paren>,
|
||||
pub(crate) body: T,
|
||||
}
|
||||
|
||||
crate::fold::impl_fold! {
|
||||
struct HdlAttr<T,> {
|
||||
struct HdlAttr<T, KW,> {
|
||||
pound_token: Pound,
|
||||
style: AttrStyle,
|
||||
bracket_token: syn::token::Bracket,
|
||||
hdl: kw::hdl,
|
||||
kw: KW,
|
||||
paren_token: Option<syn::token::Paren>,
|
||||
body: T,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T> HdlAttr<T> {
|
||||
pub(crate) fn split_body(self) -> (HdlAttr<()>, T) {
|
||||
impl<T, KW> HdlAttr<T, KW> {
|
||||
pub(crate) fn split_body(self) -> (HdlAttr<(), KW>, T) {
|
||||
let Self {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
} = self;
|
||||
|
@ -104,19 +122,19 @@ impl<T> HdlAttr<T> {
|
|||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body: (),
|
||||
},
|
||||
body,
|
||||
)
|
||||
}
|
||||
pub(crate) fn replace_body<T2>(self, body: T2) -> HdlAttr<T2> {
|
||||
pub(crate) fn replace_body<T2>(self, body: T2) -> HdlAttr<T2, KW> {
|
||||
let Self {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body: _,
|
||||
} = self;
|
||||
|
@ -124,17 +142,20 @@ impl<T> HdlAttr<T> {
|
|||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
}
|
||||
}
|
||||
pub(crate) fn as_ref(&self) -> HdlAttr<&T> {
|
||||
pub(crate) fn as_ref(&self) -> HdlAttr<&T, KW>
|
||||
where
|
||||
KW: Clone,
|
||||
{
|
||||
let Self {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
ref kw,
|
||||
paren_token,
|
||||
ref body,
|
||||
} = *self;
|
||||
|
@ -142,17 +163,20 @@ impl<T> HdlAttr<T> {
|
|||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw: kw.clone(),
|
||||
paren_token,
|
||||
body,
|
||||
}
|
||||
}
|
||||
pub(crate) fn try_map<R, E, F: FnOnce(T) -> Result<R, E>>(self, f: F) -> Result<HdlAttr<R>, E> {
|
||||
pub(crate) fn try_map<R, E, F: FnOnce(T) -> Result<R, E>>(
|
||||
self,
|
||||
f: F,
|
||||
) -> Result<HdlAttr<R, KW>, E> {
|
||||
let Self {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
} = self;
|
||||
|
@ -160,17 +184,17 @@ impl<T> HdlAttr<T> {
|
|||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body: f(body)?,
|
||||
})
|
||||
}
|
||||
pub(crate) fn map<R, F: FnOnce(T) -> R>(self, f: F) -> HdlAttr<R> {
|
||||
pub(crate) fn map<R, F: FnOnce(T) -> R>(self, f: F) -> HdlAttr<R, KW> {
|
||||
let Self {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
} = self;
|
||||
|
@ -178,7 +202,7 @@ impl<T> HdlAttr<T> {
|
|||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body: f(body),
|
||||
}
|
||||
|
@ -186,31 +210,32 @@ impl<T> HdlAttr<T> {
|
|||
fn to_attr(&self) -> Attribute
|
||||
where
|
||||
T: ToTokens,
|
||||
KW: ToTokens,
|
||||
{
|
||||
parse_quote! { #self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for HdlAttr<T> {
|
||||
impl<T: Default, KW: Default> Default for HdlAttr<T, KW> {
|
||||
fn default() -> Self {
|
||||
T::default().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for HdlAttr<T> {
|
||||
impl<T, KW: Default> From<T> for HdlAttr<T, KW> {
|
||||
fn from(body: T) -> Self {
|
||||
HdlAttr {
|
||||
pound_token: Default::default(),
|
||||
style: AttrStyle::Outer,
|
||||
bracket_token: Default::default(),
|
||||
hdl: Default::default(),
|
||||
kw: Default::default(),
|
||||
paren_token: Default::default(),
|
||||
body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for HdlAttr<T> {
|
||||
impl<T: ToTokens, KW: ToTokens + Spanned> ToTokens for HdlAttr<T, KW> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.pound_token.to_tokens(tokens);
|
||||
match self.style {
|
||||
|
@ -218,7 +243,7 @@ impl<T: ToTokens> ToTokens for HdlAttr<T> {
|
|||
AttrStyle::Outer => {}
|
||||
};
|
||||
self.bracket_token.surround(tokens, |tokens| {
|
||||
self.hdl.to_tokens(tokens);
|
||||
self.kw.to_tokens(tokens);
|
||||
match self.paren_token {
|
||||
Some(paren_token) => {
|
||||
paren_token.surround(tokens, |tokens| self.body.to_tokens(tokens))
|
||||
|
@ -226,7 +251,7 @@ impl<T: ToTokens> ToTokens for HdlAttr<T> {
|
|||
None => {
|
||||
let body = self.body.to_token_stream();
|
||||
if !body.is_empty() {
|
||||
syn::token::Paren(self.hdl.span)
|
||||
syn::token::Paren(self.kw.span())
|
||||
.surround(tokens, |tokens| tokens.extend([body]));
|
||||
}
|
||||
}
|
||||
|
@ -235,18 +260,24 @@ impl<T: ToTokens> ToTokens for HdlAttr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_hdl_attr(attr: &Attribute) -> bool {
|
||||
attr.path().is_ident("hdl")
|
||||
fn is_hdl_attr<KW: CustomToken>(attr: &Attribute) -> bool {
|
||||
attr.path().is_ident(KW::IDENT_STR)
|
||||
}
|
||||
|
||||
impl<T: Parse> HdlAttr<T> {
|
||||
fn parse_and_take_attr(attrs: &mut Vec<Attribute>) -> syn::Result<Option<Self>> {
|
||||
impl<T: Parse, KW: Parse> HdlAttr<T, KW> {
|
||||
fn parse_and_take_attr(attrs: &mut Vec<Attribute>) -> syn::Result<Option<Self>>
|
||||
where
|
||||
KW: ToTokens,
|
||||
{
|
||||
let mut retval = None;
|
||||
let mut errors = Errors::new();
|
||||
attrs.retain(|attr| {
|
||||
if is_hdl_attr(attr) {
|
||||
if let Ok(kw) = syn::parse2::<KW>(attr.path().to_token_stream()) {
|
||||
if retval.is_some() {
|
||||
errors.push(Error::new_spanned(attr, "more than one #[hdl] attribute"));
|
||||
errors.push(Error::new_spanned(
|
||||
attr,
|
||||
format_args!("more than one #[{}] attribute", kw.to_token_stream()),
|
||||
));
|
||||
}
|
||||
errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v)));
|
||||
false
|
||||
|
@ -257,13 +288,19 @@ impl<T: Parse> HdlAttr<T> {
|
|||
errors.finish()?;
|
||||
Ok(retval)
|
||||
}
|
||||
fn parse_and_leave_attr(attrs: &[Attribute]) -> syn::Result<Option<Self>> {
|
||||
fn parse_and_leave_attr(attrs: &[Attribute]) -> syn::Result<Option<Self>>
|
||||
where
|
||||
KW: ToTokens,
|
||||
{
|
||||
let mut retval = None;
|
||||
let mut errors = Errors::new();
|
||||
for attr in attrs {
|
||||
if is_hdl_attr(attr) {
|
||||
if let Ok(kw) = syn::parse2::<KW>(attr.path().to_token_stream()) {
|
||||
if retval.is_some() {
|
||||
errors.push(Error::new_spanned(attr, "more than one #[hdl] attribute"));
|
||||
errors.push(Error::new_spanned(
|
||||
attr,
|
||||
format_args!("more than one #[{}] attribute", kw.to_token_stream()),
|
||||
));
|
||||
}
|
||||
errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v)));
|
||||
}
|
||||
|
@ -284,7 +321,7 @@ impl<T: Parse> HdlAttr<T> {
|
|||
) -> syn::Result<Self> {
|
||||
let bracket_content;
|
||||
let bracket_token = bracketed!(bracket_content in input);
|
||||
let hdl = bracket_content.parse()?;
|
||||
let kw = bracket_content.parse()?;
|
||||
let paren_content;
|
||||
let body;
|
||||
let paren_token;
|
||||
|
@ -305,7 +342,7 @@ impl<T: Parse> HdlAttr<T> {
|
|||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
hdl,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
})
|
||||
|
@ -852,25 +889,31 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
let options = syn::parse2::<module::ConfigOptions>(attr)?;
|
||||
let options = HdlAttr::from(options);
|
||||
let func = syn::parse2::<module::ModuleFn>(quote! { #options #item })?;
|
||||
fn hdl_module_impl(item: ItemFn) -> syn::Result<TokenStream> {
|
||||
let func = module::ModuleFn::parse_from_fn(item)?;
|
||||
let options = func.config_options();
|
||||
let mut contents = func.generate();
|
||||
if options.body.outline_generated.is_some() {
|
||||
if options.outline_generated.is_some() {
|
||||
contents = outline_generated(contents, "module-");
|
||||
}
|
||||
Ok(contents)
|
||||
}
|
||||
|
||||
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
let kw = kw::hdl_module::default();
|
||||
hdl_module_impl(syn::parse2(quote! { #[#kw(#attr)] #item })?)
|
||||
}
|
||||
|
||||
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
let item = syn::parse2::<Item>(quote! { #[hdl(#attr)] #item })?;
|
||||
let kw = kw::hdl::default();
|
||||
let item = syn::parse2::<Item>(quote! { #[#kw(#attr)] #item })?;
|
||||
match item {
|
||||
Item::Enum(item) => hdl_enum::hdl_enum(item),
|
||||
Item::Struct(item) => hdl_bundle::hdl_bundle(item),
|
||||
Item::Fn(item) => hdl_module_impl(item),
|
||||
_ => Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"top-level #[hdl] can only be used on structs or enums",
|
||||
"top-level #[hdl] can only be used on structs, enums, or functions",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue