forked from libre-chip/fayalite
		
	support #[hdl] type aliases
This commit is contained in:
		
							parent
							
								
									20cf0abbcc
								
							
						
					
					
						commit
						ee15fd2b94
					
				
					 4 changed files with 148 additions and 3 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue