support #[hdl] on functions -- enables #[hdl] usage in function body
This commit is contained in:
parent
a8c804ef4a
commit
ff94dda922
|
@ -19,13 +19,13 @@ use syn::{
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ParsedBundle {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<ItemOptions>,
|
||||
pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
pub(crate) vis: Visibility,
|
||||
pub(crate) struct_token: Token![struct],
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
|
||||
pub(crate) fields: MaybeParsed<ParsedFieldsNamed, FieldsNamed>,
|
||||
pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip>>>,
|
||||
pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip, kw::hdl>>>,
|
||||
pub(crate) mask_type_ident: Ident,
|
||||
pub(crate) mask_type_match_variant_ident: Ident,
|
||||
pub(crate) match_variant_ident: Ident,
|
||||
|
@ -38,7 +38,7 @@ impl ParsedBundle {
|
|||
errors: &mut Errors,
|
||||
field: &mut Field,
|
||||
index: usize,
|
||||
) -> Option<HdlAttr<kw::flip>> {
|
||||
) -> Option<HdlAttr<kw::flip, kw::hdl>> {
|
||||
let Field {
|
||||
attrs,
|
||||
vis: _,
|
||||
|
@ -71,7 +71,9 @@ impl ParsedBundle {
|
|||
} = item;
|
||||
let mut errors = Errors::new();
|
||||
let mut options = errors
|
||||
.unwrap_or_default(HdlAttr::<ItemOptions>::parse_and_take_attr(&mut attrs))
|
||||
.unwrap_or_default(HdlAttr::<ItemOptions, kw::hdl>::parse_and_take_attr(
|
||||
&mut attrs,
|
||||
))
|
||||
.unwrap_or_default();
|
||||
errors.ok(options.body.validate());
|
||||
let ItemOptions {
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics,
|
||||
ParsedType, SplitForImpl, TypesParser, WrappedInConst,
|
||||
},
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
kw, Errors, HdlAttr, PairsIterExt,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote_spanned, ToTokens};
|
||||
|
@ -29,7 +29,7 @@ crate::options! {
|
|||
pub(crate) struct ParsedVariantField {
|
||||
pub(crate) paren_token: Paren,
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<FieldOptions>,
|
||||
pub(crate) options: HdlAttr<FieldOptions, kw::hdl>,
|
||||
pub(crate) ty: MaybeParsed<ParsedType, Type>,
|
||||
pub(crate) comma_token: Option<Token![,]>,
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ pub(crate) struct ParsedVariantField {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ParsedVariant {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<VariantOptions>,
|
||||
pub(crate) options: HdlAttr<VariantOptions, kw::hdl>,
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) field: Option<ParsedVariantField>,
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ impl ParsedVariant {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ParsedEnum {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<ItemOptions>,
|
||||
pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
pub(crate) vis: Visibility,
|
||||
pub(crate) enum_token: Token![enum],
|
||||
pub(crate) ident: Ident,
|
||||
|
@ -142,7 +142,9 @@ impl ParsedEnum {
|
|||
} = item;
|
||||
let mut errors = Errors::new();
|
||||
let mut options = errors
|
||||
.unwrap_or_default(HdlAttr::<ItemOptions>::parse_and_take_attr(&mut attrs))
|
||||
.unwrap_or_default(HdlAttr::<ItemOptions, kw::hdl>::parse_and_take_attr(
|
||||
&mut attrs,
|
||||
))
|
||||
.unwrap_or_default();
|
||||
errors.ok(options.body.validate());
|
||||
let ItemOptions {
|
||||
|
|
|
@ -1745,7 +1745,7 @@ impl<T: ParseTypes<I>, I, P: Clone> ParseTypes<Punctuated<I, P>> for Punctuated<
|
|||
pub(crate) enum UnparsedGenericParam {
|
||||
Type {
|
||||
attrs: Vec<Attribute>,
|
||||
options: HdlAttr<TypeParamOptions>,
|
||||
options: HdlAttr<TypeParamOptions, kw::hdl>,
|
||||
ident: Ident,
|
||||
colon_token: Token![:],
|
||||
bounds: ParsedBounds,
|
||||
|
@ -1753,7 +1753,7 @@ pub(crate) enum UnparsedGenericParam {
|
|||
},
|
||||
Const {
|
||||
attrs: Vec<Attribute>,
|
||||
options: HdlAttr<ConstParamOptions>,
|
||||
options: HdlAttr<ConstParamOptions, kw::hdl>,
|
||||
const_token: Token![const],
|
||||
ident: Ident,
|
||||
colon_token: Token![:],
|
||||
|
@ -2278,7 +2278,7 @@ impl ParsedBound {
|
|||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ParsedTypeParam {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<TypeParamOptions>,
|
||||
pub(crate) options: HdlAttr<TypeParamOptions, kw::hdl>,
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) colon_token: Token![:],
|
||||
pub(crate) bounds: ParsedTypeBounds,
|
||||
|
@ -2312,7 +2312,7 @@ impl ToTokens for ParsedTypeParam {
|
|||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ParsedSizeTypeParam {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<TypeParamOptions>,
|
||||
pub(crate) options: HdlAttr<TypeParamOptions, kw::hdl>,
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) colon_token: Token![:],
|
||||
pub(crate) bounds: ParsedSizeTypeBounds,
|
||||
|
@ -2356,7 +2356,7 @@ pub(crate) struct ParsedConstParamWhereBounds {
|
|||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ParsedConstParam {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<ConstParamOptions>,
|
||||
pub(crate) options: HdlAttr<ConstParamOptions, kw::hdl>,
|
||||
pub(crate) const_token: Token![const],
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) colon_token: Token![:],
|
||||
|
@ -2413,7 +2413,7 @@ impl ParsedGenericParam {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct ParsedGenerics {
|
||||
pub(crate) lt_token: Option<Token![<]>,
|
||||
pub(crate) params: Punctuated<ParsedGenericParam, Token![,]>,
|
||||
|
@ -2863,9 +2863,11 @@ impl ParsedGenerics {
|
|||
let (input_param, punct) = input_param.into_tuple();
|
||||
let (unparsed_param, late_parsed_param) = match input_param {
|
||||
GenericParam::Lifetime(param) => {
|
||||
errors.unwrap_or_default(HdlAttr::<LifetimeParamOptions>::parse_and_take_attr(
|
||||
errors.unwrap_or_default(
|
||||
HdlAttr::<LifetimeParamOptions, kw::hdl>::parse_and_take_attr(
|
||||
&mut param.attrs,
|
||||
));
|
||||
),
|
||||
);
|
||||
errors.error(param, "lifetime generics are not supported by #[hdl]");
|
||||
continue;
|
||||
}
|
||||
|
@ -2879,7 +2881,9 @@ impl ParsedGenerics {
|
|||
}) => {
|
||||
let span = ident.span();
|
||||
let options = errors
|
||||
.unwrap_or_default(HdlAttr::<TypeParamOptions>::parse_and_take_attr(attrs))
|
||||
.unwrap_or_default(
|
||||
HdlAttr::<TypeParamOptions, kw::hdl>::parse_and_take_attr(attrs),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
let colon_token = colon_token.unwrap_or_else(|| Token![:](span));
|
||||
if !bounds.is_empty() {
|
||||
|
@ -2917,7 +2921,9 @@ impl ParsedGenerics {
|
|||
default,
|
||||
}) => {
|
||||
let options = errors
|
||||
.unwrap_or_default(HdlAttr::<ConstParamOptions>::parse_and_take_attr(attrs))
|
||||
.unwrap_or_default(
|
||||
HdlAttr::<ConstParamOptions, kw::hdl>::parse_and_take_attr(attrs),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
if let Some(default) = default {
|
||||
let _ = eq_token;
|
||||
|
|
|
@ -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",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
hdl_type_common::{ParsedGenerics, SplitForImpl},
|
||||
kw,
|
||||
module::transform_body::{HdlLet, HdlLetKindIO},
|
||||
options, Errors, HdlAttr, PairsIterExt,
|
||||
};
|
||||
|
@ -9,7 +10,6 @@ use proc_macro2::TokenStream;
|
|||
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||
use std::collections::HashSet;
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
parse_quote,
|
||||
visit::{visit_pat, Visit},
|
||||
Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct,
|
||||
|
@ -59,9 +59,9 @@ impl Visit<'_> for CheckNameConflictsWithModuleBuilderVisitor<'_> {
|
|||
|
||||
pub(crate) type ModuleIO = HdlLet<HdlLetKindIO>;
|
||||
|
||||
pub(crate) struct ModuleFn {
|
||||
struct ModuleFnModule {
|
||||
attrs: Vec<Attribute>,
|
||||
config_options: HdlAttr<ConfigOptions>,
|
||||
config_options: HdlAttr<ConfigOptions, kw::hdl_module>,
|
||||
module_kind: ModuleKind,
|
||||
vis: Visibility,
|
||||
sig: Signature,
|
||||
|
@ -70,6 +70,26 @@ pub(crate) struct ModuleFn {
|
|||
the_struct: TokenStream,
|
||||
}
|
||||
|
||||
enum ModuleFnImpl {
|
||||
Module(ModuleFnModule),
|
||||
Fn {
|
||||
attrs: Vec<Attribute>,
|
||||
config_options: HdlAttr<ConfigOptions, kw::hdl>,
|
||||
vis: Visibility,
|
||||
sig: Signature,
|
||||
block: Box<Block>,
|
||||
},
|
||||
}
|
||||
|
||||
options! {
|
||||
pub(crate) enum HdlOrHdlModule {
|
||||
Hdl(hdl),
|
||||
HdlModule(hdl_module),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ModuleFn(ModuleFnImpl);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub(crate) enum ModuleKind {
|
||||
Extern,
|
||||
|
@ -89,14 +109,25 @@ impl Visit<'_> for ContainsSkippedIdent<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Parse for ModuleFn {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
impl ModuleFn {
|
||||
pub(crate) fn config_options(&self) -> ConfigOptions {
|
||||
let (ModuleFnImpl::Module(ModuleFnModule {
|
||||
config_options: HdlAttr { body, .. },
|
||||
..
|
||||
})
|
||||
| ModuleFnImpl::Fn {
|
||||
config_options: HdlAttr { body, .. },
|
||||
..
|
||||
}) = &self.0;
|
||||
body.clone()
|
||||
}
|
||||
pub(crate) fn parse_from_fn(item: ItemFn) -> syn::Result<Self> {
|
||||
let ItemFn {
|
||||
mut attrs,
|
||||
vis,
|
||||
mut sig,
|
||||
block,
|
||||
} = input.parse()?;
|
||||
} = item;
|
||||
let Signature {
|
||||
ref constness,
|
||||
ref asyncness,
|
||||
|
@ -111,17 +142,33 @@ impl Parse for ModuleFn {
|
|||
ref output,
|
||||
} = sig;
|
||||
let mut errors = Errors::new();
|
||||
let config_options = errors
|
||||
.unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs))
|
||||
.unwrap_or_default();
|
||||
let Some(mut config_options) =
|
||||
errors.unwrap_or_default(
|
||||
HdlAttr::<ConfigOptions, HdlOrHdlModule>::parse_and_take_attr(&mut attrs),
|
||||
)
|
||||
else {
|
||||
errors.error(sig.ident, "missing #[hdl] or #[hdl_module] attribute");
|
||||
errors.finish()?;
|
||||
unreachable!();
|
||||
};
|
||||
let ConfigOptions {
|
||||
outline_generated: _,
|
||||
extern_,
|
||||
} = config_options.body;
|
||||
let module_kind = match extern_ {
|
||||
Some(_) => ModuleKind::Extern,
|
||||
None => ModuleKind::Normal,
|
||||
let module_kind = match (config_options.kw, extern_) {
|
||||
(HdlOrHdlModule::Hdl(_), None) => None,
|
||||
(HdlOrHdlModule::Hdl(_), Some(extern2)) => {
|
||||
config_options.body.extern_ = None;
|
||||
errors.error(
|
||||
extern2.0,
|
||||
"extern can only be used as #[hdl_module(extern)]",
|
||||
);
|
||||
None
|
||||
}
|
||||
(HdlOrHdlModule::HdlModule(_), None) => Some(ModuleKind::Normal),
|
||||
(HdlOrHdlModule::HdlModule(_), Some(_)) => Some(ModuleKind::Extern),
|
||||
};
|
||||
if let HdlOrHdlModule::HdlModule(_) = config_options.kw {
|
||||
for fn_arg in inputs {
|
||||
match fn_arg {
|
||||
FnArg::Receiver(_) => {
|
||||
|
@ -149,20 +196,24 @@ impl Parse for ModuleFn {
|
|||
if let Some(abi) = abi {
|
||||
errors.push(syn::Error::new_spanned(abi, "extern not allowed here"));
|
||||
}
|
||||
}
|
||||
let mut skipped_idents = HashSet::new();
|
||||
let struct_generic_params = generics
|
||||
.params
|
||||
.pairs_mut()
|
||||
.filter_map_pair_value_mut(|v| match v {
|
||||
GenericParam::Lifetime(LifetimeParam { attrs, .. }) => {
|
||||
errors
|
||||
.unwrap_or_default(HdlAttr::<crate::kw::skip>::parse_and_take_attr(attrs));
|
||||
errors.unwrap_or_default(
|
||||
HdlAttr::<crate::kw::skip, kw::hdl>::parse_and_take_attr(attrs),
|
||||
);
|
||||
None
|
||||
}
|
||||
GenericParam::Type(TypeParam { attrs, ident, .. })
|
||||
| GenericParam::Const(ConstParam { attrs, ident, .. }) => {
|
||||
if errors
|
||||
.unwrap_or_default(HdlAttr::<crate::kw::skip>::parse_and_take_attr(attrs))
|
||||
.unwrap_or_default(
|
||||
HdlAttr::<crate::kw::skip, kw::hdl>::parse_and_take_attr(attrs),
|
||||
)
|
||||
.is_some()
|
||||
{
|
||||
skipped_idents.insert(ident.clone());
|
||||
|
@ -176,6 +227,7 @@ impl Parse for ModuleFn {
|
|||
let struct_where_clause = generics
|
||||
.where_clause
|
||||
.as_mut()
|
||||
.filter(|_| matches!(config_options.kw, HdlOrHdlModule::HdlModule(_)))
|
||||
.map(|where_clause| WhereClause {
|
||||
where_token: where_clause.where_token,
|
||||
predicates: where_clause
|
||||
|
@ -198,7 +250,8 @@ impl Parse for ModuleFn {
|
|||
})
|
||||
.collect(),
|
||||
});
|
||||
let struct_generics = Generics {
|
||||
let struct_generics = if let HdlOrHdlModule::HdlModule(_) = config_options.kw {
|
||||
let mut struct_generics = Generics {
|
||||
lt_token: generics.lt_token,
|
||||
params: struct_generic_params,
|
||||
gt_token: generics.gt_token,
|
||||
|
@ -213,7 +266,10 @@ impl Parse for ModuleFn {
|
|||
"return type not allowed here",
|
||||
));
|
||||
}
|
||||
let struct_generics = errors.ok(ParsedGenerics::parse(&mut { struct_generics }));
|
||||
errors.ok(ParsedGenerics::parse(&mut struct_generics))
|
||||
} else {
|
||||
Some(ParsedGenerics::default())
|
||||
};
|
||||
let body_results = struct_generics.as_ref().and_then(|struct_generics| {
|
||||
errors.ok(transform_body::transform_body(
|
||||
module_kind,
|
||||
|
@ -224,6 +280,47 @@ impl Parse for ModuleFn {
|
|||
errors.finish()?;
|
||||
let struct_generics = struct_generics.unwrap();
|
||||
let (block, io) = body_results.unwrap();
|
||||
let config_options = match config_options {
|
||||
HdlAttr {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
kw: HdlOrHdlModule::Hdl((kw,)),
|
||||
paren_token,
|
||||
body,
|
||||
} => {
|
||||
debug_assert!(io.is_empty());
|
||||
return Ok(Self(ModuleFnImpl::Fn {
|
||||
attrs,
|
||||
config_options: HdlAttr {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
},
|
||||
vis,
|
||||
sig,
|
||||
block,
|
||||
}));
|
||||
}
|
||||
HdlAttr {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
kw: HdlOrHdlModule::HdlModule((kw,)),
|
||||
paren_token,
|
||||
body,
|
||||
} => HdlAttr {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
kw,
|
||||
paren_token,
|
||||
body,
|
||||
},
|
||||
};
|
||||
let (_struct_impl_generics, _struct_type_generics, struct_where_clause) =
|
||||
struct_generics.split_for_impl();
|
||||
let struct_where_clause: Option<WhereClause> = parse_quote! { #struct_where_clause };
|
||||
|
@ -259,22 +356,22 @@ impl Parse for ModuleFn {
|
|||
}
|
||||
};
|
||||
let the_struct = crate::hdl_bundle::hdl_bundle(the_struct)?;
|
||||
Ok(Self {
|
||||
Ok(Self(ModuleFnImpl::Module(ModuleFnModule {
|
||||
attrs,
|
||||
config_options,
|
||||
module_kind,
|
||||
module_kind: module_kind.unwrap(),
|
||||
vis,
|
||||
sig,
|
||||
block,
|
||||
struct_generics,
|
||||
the_struct,
|
||||
})
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleFn {
|
||||
pub(crate) fn generate(self) -> TokenStream {
|
||||
let Self {
|
||||
let ModuleFnModule {
|
||||
attrs,
|
||||
config_options,
|
||||
module_kind,
|
||||
|
@ -283,7 +380,28 @@ impl ModuleFn {
|
|||
block,
|
||||
struct_generics,
|
||||
the_struct,
|
||||
} = self;
|
||||
} = match self.0 {
|
||||
ModuleFnImpl::Module(v) => v,
|
||||
ModuleFnImpl::Fn {
|
||||
attrs,
|
||||
config_options,
|
||||
vis,
|
||||
sig,
|
||||
block,
|
||||
} => {
|
||||
let ConfigOptions {
|
||||
outline_generated: _,
|
||||
extern_: _,
|
||||
} = config_options.body;
|
||||
return ItemFn {
|
||||
attrs,
|
||||
vis,
|
||||
sig,
|
||||
block,
|
||||
}
|
||||
.into_token_stream();
|
||||
}
|
||||
};
|
||||
let ConfigOptions {
|
||||
outline_generated: _,
|
||||
extern_: _,
|
||||
|
|
|
@ -925,7 +925,7 @@ with_debug_clone_and_fold! {
|
|||
#[allow(dead_code)]
|
||||
pub(crate) struct HdlLet<Kind = HdlLetKind> {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) hdl_attr: HdlAttr<Nothing>,
|
||||
pub(crate) hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
pub(crate) let_token: Token![let],
|
||||
pub(crate) mut_token: Option<Token![mut]>,
|
||||
pub(crate) name: Ident,
|
||||
|
@ -1112,7 +1112,7 @@ impl<T: ToString> ToTokens for ImplicitName<T> {
|
|||
}
|
||||
|
||||
struct Visitor<'a> {
|
||||
module_kind: ModuleKind,
|
||||
module_kind: Option<ModuleKind>,
|
||||
errors: Errors,
|
||||
io: Vec<ModuleIO>,
|
||||
block_depth: usize,
|
||||
|
@ -1120,22 +1120,33 @@ struct Visitor<'a> {
|
|||
}
|
||||
|
||||
impl Visitor<'_> {
|
||||
fn take_hdl_attr<T: Parse>(&mut self, attrs: &mut Vec<Attribute>) -> Option<HdlAttr<T>> {
|
||||
fn take_hdl_attr<T: Parse>(
|
||||
&mut self,
|
||||
attrs: &mut Vec<Attribute>,
|
||||
) -> Option<HdlAttr<T, kw::hdl>> {
|
||||
self.errors.unwrap_or(
|
||||
HdlAttr::parse_and_take_attr(attrs),
|
||||
Some(syn::parse2::<T>(quote! {}).unwrap().into()),
|
||||
)
|
||||
}
|
||||
fn require_normal_module(&mut self, spanned: impl ToTokens) {
|
||||
fn require_normal_module_or_fn(&mut self, spanned: impl ToTokens) {
|
||||
match self.module_kind {
|
||||
ModuleKind::Extern => {
|
||||
Some(ModuleKind::Extern) => {
|
||||
self.errors
|
||||
.error(spanned, "not allowed in #[hdl_module(extern)]");
|
||||
}
|
||||
ModuleKind::Normal => {}
|
||||
Some(ModuleKind::Normal) | None => {}
|
||||
}
|
||||
}
|
||||
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing>, expr_if: ExprIf) -> Expr {
|
||||
fn require_module(&mut self, spanned: impl ToTokens) {
|
||||
match self.module_kind {
|
||||
None => {
|
||||
self.errors.error(spanned, "not allowed in #[hdl] fn");
|
||||
}
|
||||
Some(_) => {}
|
||||
}
|
||||
}
|
||||
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing, kw::hdl>, expr_if: ExprIf) -> Expr {
|
||||
let ExprIf {
|
||||
attrs,
|
||||
if_token,
|
||||
|
@ -1143,7 +1154,7 @@ impl Visitor<'_> {
|
|||
then_branch,
|
||||
else_branch,
|
||||
} = expr_if;
|
||||
self.require_normal_module(if_token);
|
||||
self.require_normal_module_or_fn(if_token);
|
||||
let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr {
|
||||
Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if),
|
||||
expr => expr,
|
||||
|
@ -1208,11 +1219,12 @@ impl Visitor<'_> {
|
|||
.to_tokens(expr);
|
||||
});
|
||||
let mut attrs = hdl_let.attrs.clone();
|
||||
self.require_module(kind);
|
||||
match self.module_kind {
|
||||
ModuleKind::Extern => attrs.push(parse_quote_spanned! {hdl_let.let_token.span=>
|
||||
Some(ModuleKind::Extern) => attrs.push(parse_quote_spanned! {hdl_let.let_token.span=>
|
||||
#[allow(unused_variables)]
|
||||
}),
|
||||
ModuleKind::Normal => {}
|
||||
Some(ModuleKind::Normal) | None => {}
|
||||
}
|
||||
let let_stmt = Local {
|
||||
attrs,
|
||||
|
@ -1249,7 +1261,7 @@ impl Visitor<'_> {
|
|||
},
|
||||
semi_token,
|
||||
} = hdl_let;
|
||||
self.require_normal_module(instance);
|
||||
self.require_normal_module_or_fn(instance);
|
||||
let mut expr = instance.to_token_stream();
|
||||
paren.surround(&mut expr, |expr| {
|
||||
let name_str = ImplicitName {
|
||||
|
@ -1276,7 +1288,7 @@ impl Visitor<'_> {
|
|||
fn process_hdl_let_reg_builder(&mut self, hdl_let: HdlLet<HdlLetKindRegBuilder>) -> Local {
|
||||
let name = &hdl_let.name;
|
||||
let reg_builder = hdl_let.kind.reg_builder;
|
||||
self.require_normal_module(reg_builder);
|
||||
self.require_normal_module_or_fn(reg_builder);
|
||||
let mut expr = reg_builder.to_token_stream();
|
||||
hdl_let.kind.reg_builder_paren.surround(&mut expr, |expr| {
|
||||
let name_str = ImplicitName {
|
||||
|
@ -1327,7 +1339,7 @@ impl Visitor<'_> {
|
|||
fn process_hdl_let_wire(&mut self, hdl_let: HdlLet<HdlLetKindWire>) -> Local {
|
||||
let name = &hdl_let.name;
|
||||
let wire = hdl_let.kind.wire;
|
||||
self.require_normal_module(wire);
|
||||
self.require_normal_module_or_fn(wire);
|
||||
let ty_expr = unwrap_or_static_type(hdl_let.kind.ty_expr.as_ref(), wire.span());
|
||||
let mut expr = wire.to_token_stream();
|
||||
hdl_let.kind.paren.surround(&mut expr, |expr| {
|
||||
|
@ -1361,7 +1373,7 @@ impl Visitor<'_> {
|
|||
let name = &hdl_let.name;
|
||||
let memory_fn = hdl_let.kind.memory_fn;
|
||||
let memory_fn_name = memory_fn.name();
|
||||
self.require_normal_module(memory_fn_name);
|
||||
self.require_normal_module_or_fn(memory_fn_name);
|
||||
let mut expr = memory_fn_name.to_token_stream();
|
||||
let (paren, arg) = match memory_fn {
|
||||
MemoryFn::Memory {
|
||||
|
@ -1543,7 +1555,7 @@ impl Fold for Visitor<'_> {
|
|||
}
|
||||
|
||||
fn fold_attribute(&mut self, attr: Attribute) -> Attribute {
|
||||
if is_hdl_attr(&attr) {
|
||||
if is_hdl_attr::<kw::hdl>(&attr) {
|
||||
self.errors
|
||||
.error(&attr, "#[hdl] attribute not supported here");
|
||||
}
|
||||
|
@ -1610,8 +1622,9 @@ impl Fold for Visitor<'_> {
|
|||
fn fold_local(&mut self, let_stmt: Local) -> Local {
|
||||
match self
|
||||
.errors
|
||||
.ok(HdlAttr::<Nothing>::parse_and_leave_attr(&let_stmt.attrs))
|
||||
{
|
||||
.ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr(
|
||||
&let_stmt.attrs,
|
||||
)) {
|
||||
None => return empty_let(),
|
||||
Some(None) => return fold_local(self, let_stmt),
|
||||
Some(Some(HdlAttr { .. })) => {}
|
||||
|
@ -1646,7 +1659,7 @@ impl Fold for Visitor<'_> {
|
|||
}
|
||||
|
||||
pub(crate) fn transform_body(
|
||||
module_kind: ModuleKind,
|
||||
module_kind: Option<ModuleKind>,
|
||||
mut body: Box<Block>,
|
||||
parsed_generics: &ParsedGenerics,
|
||||
) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{module::transform_body::Visitor, HdlAttr};
|
||||
use crate::{kw, module::transform_body::Visitor, HdlAttr};
|
||||
use quote::{format_ident, quote_spanned};
|
||||
use syn::{
|
||||
parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
|
||||
|
@ -10,10 +10,10 @@ use syn::{
|
|||
impl Visitor<'_> {
|
||||
pub(crate) fn process_hdl_array(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
mut expr_array: ExprArray,
|
||||
) -> Expr {
|
||||
self.require_normal_module(hdl_attr);
|
||||
self.require_normal_module_or_fn(hdl_attr);
|
||||
for elem in &mut expr_array.elems {
|
||||
*elem = parse_quote_spanned! {elem.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&(#elem))
|
||||
|
@ -23,10 +23,10 @@ impl Visitor<'_> {
|
|||
}
|
||||
pub(crate) fn process_hdl_repeat(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
mut expr_repeat: ExprRepeat,
|
||||
) -> Expr {
|
||||
self.require_normal_module(hdl_attr);
|
||||
self.require_normal_module_or_fn(hdl_attr);
|
||||
let repeated_value = &expr_repeat.expr;
|
||||
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
|
||||
|
@ -35,10 +35,10 @@ impl Visitor<'_> {
|
|||
}
|
||||
pub(crate) fn process_hdl_struct(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
expr_struct: ExprStruct,
|
||||
) -> Expr {
|
||||
self.require_normal_module(&hdl_attr);
|
||||
self.require_normal_module_or_fn(&hdl_attr);
|
||||
let name_span = expr_struct.path.segments.last().unwrap().ident.span();
|
||||
let builder_ident = format_ident!("__builder", span = name_span);
|
||||
let empty_builder = if expr_struct.qself.is_some()
|
||||
|
@ -91,10 +91,10 @@ impl Visitor<'_> {
|
|||
}
|
||||
pub(crate) fn process_hdl_tuple(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
expr_tuple: ExprTuple,
|
||||
) -> Expr {
|
||||
self.require_normal_module(hdl_attr);
|
||||
self.require_normal_module_or_fn(hdl_attr);
|
||||
parse_quote_spanned! {expr_tuple.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
fold::{impl_fold, DoFold},
|
||||
kw,
|
||||
module::transform_body::{with_debug_clone_and_fold, Visitor},
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
};
|
||||
|
@ -749,7 +750,7 @@ struct HdlMatchParseState<'a> {
|
|||
impl Visitor<'_> {
|
||||
pub(crate) fn process_hdl_match(
|
||||
&mut self,
|
||||
_hdl_attr: HdlAttr<Nothing>,
|
||||
_hdl_attr: HdlAttr<Nothing, kw::hdl>,
|
||||
expr_match: ExprMatch,
|
||||
) -> Expr {
|
||||
let span = expr_match.match_token.span();
|
||||
|
@ -761,7 +762,7 @@ impl Visitor<'_> {
|
|||
brace_token: _,
|
||||
arms,
|
||||
} = expr_match;
|
||||
self.require_normal_module(match_token);
|
||||
self.require_normal_module_or_fn(match_token);
|
||||
let mut state = HdlMatchParseState {
|
||||
match_span: span,
|
||||
errors: &mut self.errors,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: top-level #[hdl] can only be used on structs or enums
|
||||
error: top-level #[hdl] can only be used on structs, enums, or functions
|
||||
--> tests/ui/hdl_types.rs:5:1
|
||||
|
|
||||
5 | #[hdl]
|
||||
|
|
Loading…
Reference in a new issue