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 fold;
|
||||||
mod hdl_bundle;
|
mod hdl_bundle;
|
||||||
mod hdl_enum;
|
mod hdl_enum;
|
||||||
|
mod hdl_type_alias;
|
||||||
mod hdl_type_common;
|
mod hdl_type_common;
|
||||||
mod module;
|
mod module;
|
||||||
|
|
||||||
|
@ -850,6 +851,7 @@ macro_rules! options {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::hdl_type_alias::hdl_type_alias_impl;
|
||||||
pub(crate) use options;
|
pub(crate) use options;
|
||||||
|
|
||||||
pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStream {
|
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> {
|
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
|
||||||
let kw = kw::hdl::default();
|
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 {
|
match item {
|
||||||
Item::Enum(item) => hdl_enum::hdl_enum(item),
|
Item::Enum(item) => hdl_enum::hdl_enum(item),
|
||||||
Item::Struct(item) => hdl_bundle::hdl_bundle(item),
|
Item::Struct(item) => hdl_bundle::hdl_bundle(item),
|
||||||
Item::Fn(item) => hdl_module_impl(item),
|
Item::Fn(item) => hdl_module_impl(item),
|
||||||
|
Item::Type(item) => hdl_type_alias_impl(item),
|
||||||
_ => Err(syn::Error::new(
|
_ => Err(syn::Error::new(
|
||||||
Span::call_site(),
|
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,
|
A,
|
||||||
B(UInt<3>),
|
B(UInt<3>),
|
||||||
C(T),
|
C(T),
|
||||||
|
D(TyAlias2),
|
||||||
|
E(TyAlias<Bool, ConstUsize<1>, { 1 + 2 }>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(outline_generated)]
|
#[hdl(outline_generated)]
|
||||||
|
@ -38,6 +40,12 @@ pub struct S2<T = ()> {
|
||||||
pub v: E<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
|
// check that #[hdl] properly handles hygiene
|
||||||
macro_rules! types_in_macros {
|
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) => {
|
($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
|
--> tests/ui/hdl_types.rs:5:1
|
||||||
|
|
|
|
||||||
5 | #[hdl]
|
5 | #[hdl]
|
||||||
|
|
Loading…
Reference in a new issue