support #[hdl] type aliases
This commit is contained in:
parent
20cf0abbcc
commit
ee15fd2b94
133
crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs
Normal file
133
crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
hdl_type_common::{
|
||||
get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType,
|
||||
TypesParser,
|
||||
},
|
||||
kw, Errors, HdlAttr,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{parse_quote_spanned, Attribute, Generics, Ident, ItemType, Token, Type, Visibility};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ParsedTypeAlias {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
|
||||
pub(crate) vis: Visibility,
|
||||
pub(crate) type_token: Token![type],
|
||||
pub(crate) ident: Ident,
|
||||
pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
|
||||
pub(crate) eq_token: Token![=],
|
||||
pub(crate) ty: MaybeParsed<ParsedType, Type>,
|
||||
pub(crate) semi_token: Token![;],
|
||||
}
|
||||
|
||||
impl ParsedTypeAlias {
|
||||
fn parse(item: ItemType) -> syn::Result<Self> {
|
||||
let ItemType {
|
||||
mut attrs,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
mut generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
} = item;
|
||||
let mut errors = Errors::new();
|
||||
let mut options = errors
|
||||
.unwrap_or_default(HdlAttr::<ItemOptions, kw::hdl>::parse_and_take_attr(
|
||||
&mut attrs,
|
||||
))
|
||||
.unwrap_or_default();
|
||||
errors.ok(options.body.validate());
|
||||
let ItemOptions {
|
||||
outline_generated: _,
|
||||
target: _,
|
||||
custom_bounds,
|
||||
no_static,
|
||||
no_runtime_generics: _,
|
||||
} = options.body;
|
||||
if let Some((no_static,)) = no_static {
|
||||
errors.error(no_static, "no_static is not valid on type aliases");
|
||||
}
|
||||
let generics = if custom_bounds.is_some() {
|
||||
MaybeParsed::Unrecognized(generics)
|
||||
} else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
|
||||
MaybeParsed::Parsed(generics)
|
||||
} else {
|
||||
MaybeParsed::Unrecognized(generics)
|
||||
};
|
||||
let ty = TypesParser::maybe_run(generics.as_ref(), *ty, &mut errors);
|
||||
errors.finish()?;
|
||||
Ok(Self {
|
||||
attrs,
|
||||
options,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ParsedTypeAlias {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
attrs,
|
||||
options,
|
||||
vis,
|
||||
type_token,
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty,
|
||||
semi_token,
|
||||
} = self;
|
||||
let ItemOptions {
|
||||
outline_generated: _,
|
||||
target,
|
||||
custom_bounds: _,
|
||||
no_static: _,
|
||||
no_runtime_generics,
|
||||
} = &options.body;
|
||||
let target = get_target(target, ident);
|
||||
let mut type_attrs = attrs.clone();
|
||||
type_attrs.push(parse_quote_spanned! {ident.span()=>
|
||||
#[allow(type_alias_bounds)]
|
||||
});
|
||||
ItemType {
|
||||
attrs: type_attrs,
|
||||
vis: vis.clone(),
|
||||
type_token: *type_token,
|
||||
ident: ident.clone(),
|
||||
generics: generics.into(),
|
||||
eq_token: *eq_token,
|
||||
ty: Box::new(ty.clone().into()),
|
||||
semi_token: *semi_token,
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) =
|
||||
(generics, ty, no_runtime_generics)
|
||||
{
|
||||
generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
|
||||
ty.make_hdl_type_expr(context)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hdl_type_alias_impl(item: ItemType) -> syn::Result<TokenStream> {
|
||||
let item = ParsedTypeAlias::parse(item)?;
|
||||
let outline_generated = item.options.body.outline_generated;
|
||||
let mut contents = item.to_token_stream();
|
||||
if outline_generated.is_some() {
|
||||
contents = crate::outline_generated(contents, "hdl-type-alias-");
|
||||
}
|
||||
Ok(contents)
|
||||
}
|
|
@ -16,6 +16,7 @@ use syn::{
|
|||
mod fold;
|
||||
mod hdl_bundle;
|
||||
mod hdl_enum;
|
||||
mod hdl_type_alias;
|
||||
mod hdl_type_common;
|
||||
mod module;
|
||||
|
||||
|
@ -850,6 +851,7 @@ macro_rules! options {
|
|||
};
|
||||
}
|
||||
|
||||
use crate::hdl_type_alias::hdl_type_alias_impl;
|
||||
pub(crate) use options;
|
||||
|
||||
pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStream {
|
||||
|
@ -906,14 +908,16 @@ pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStre
|
|||
|
||||
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||
let kw = kw::hdl::default();
|
||||
let item = syn::parse2::<Item>(quote! { #[#kw(#attr)] #item })?;
|
||||
let item = quote! { #[#kw(#attr)] #item };
|
||||
let item = syn::parse2::<Item>(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),
|
||||
Item::Type(item) => hdl_type_alias_impl(item),
|
||||
_ => Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"top-level #[hdl] can only be used on structs, enums, or functions",
|
||||
"top-level #[hdl] can only be used on structs, enums, type aliases, or functions",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ pub enum E<T> {
|
|||
A,
|
||||
B(UInt<3>),
|
||||
C(T),
|
||||
D(TyAlias2),
|
||||
E(TyAlias<Bool, ConstUsize<1>, { 1 + 2 }>),
|
||||
}
|
||||
|
||||
#[hdl(outline_generated)]
|
||||
|
@ -38,6 +40,12 @@ pub struct S2<T = ()> {
|
|||
pub v: E<T>,
|
||||
}
|
||||
|
||||
#[hdl(outline_generated)]
|
||||
pub type TyAlias<T, Sz: Size, const C: usize, D = ()> = Array<S<T, Sz, D>, C>;
|
||||
|
||||
#[hdl(outline_generated)]
|
||||
pub type TyAlias2 = TyAlias<UInt<8>, ConstUsize<24>, 5>;
|
||||
|
||||
// check that #[hdl] properly handles hygiene
|
||||
macro_rules! types_in_macros {
|
||||
($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident, $B:ident, $C:ident, $D:ident, $E:ident, $F:ident) => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: top-level #[hdl] can only be used on structs, enums, or functions
|
||||
error: top-level #[hdl] can only be used on structs, enums, type aliases, or functions
|
||||
--> tests/ui/hdl_types.rs:5:1
|
||||
|
|
||||
5 | #[hdl]
|
||||
|
|
Loading…
Reference in a new issue