Compare commits
	
		
			4 commits
		
	
	
		
			a8c804ef4a
			...
			51ce7b079e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 51ce7b079e | |||
| ff269e5def | |||
| df55a514e4 | |||
| ff94dda922 | 
					 15 changed files with 916 additions and 167 deletions
				
			
		| 
						 | 
					@ -19,13 +19,13 @@ use syn::{
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub(crate) struct ParsedBundle {
 | 
					pub(crate) struct ParsedBundle {
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
    pub(crate) options: HdlAttr<ItemOptions>,
 | 
					    pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
 | 
				
			||||||
    pub(crate) vis: Visibility,
 | 
					    pub(crate) vis: Visibility,
 | 
				
			||||||
    pub(crate) struct_token: Token![struct],
 | 
					    pub(crate) struct_token: Token![struct],
 | 
				
			||||||
    pub(crate) ident: Ident,
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
					    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
				
			||||||
    pub(crate) fields: MaybeParsed<ParsedFieldsNamed, FieldsNamed>,
 | 
					    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_ident: Ident,
 | 
				
			||||||
    pub(crate) mask_type_match_variant_ident: Ident,
 | 
					    pub(crate) mask_type_match_variant_ident: Ident,
 | 
				
			||||||
    pub(crate) match_variant_ident: Ident,
 | 
					    pub(crate) match_variant_ident: Ident,
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@ impl ParsedBundle {
 | 
				
			||||||
        errors: &mut Errors,
 | 
					        errors: &mut Errors,
 | 
				
			||||||
        field: &mut Field,
 | 
					        field: &mut Field,
 | 
				
			||||||
        index: usize,
 | 
					        index: usize,
 | 
				
			||||||
    ) -> Option<HdlAttr<kw::flip>> {
 | 
					    ) -> Option<HdlAttr<kw::flip, kw::hdl>> {
 | 
				
			||||||
        let Field {
 | 
					        let Field {
 | 
				
			||||||
            attrs,
 | 
					            attrs,
 | 
				
			||||||
            vis: _,
 | 
					            vis: _,
 | 
				
			||||||
| 
						 | 
					@ -71,7 +71,9 @@ impl ParsedBundle {
 | 
				
			||||||
        } = item;
 | 
					        } = item;
 | 
				
			||||||
        let mut errors = Errors::new();
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
        let mut options = errors
 | 
					        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();
 | 
					            .unwrap_or_default();
 | 
				
			||||||
        errors.ok(options.body.validate());
 | 
					        errors.ok(options.body.validate());
 | 
				
			||||||
        let ItemOptions {
 | 
					        let ItemOptions {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ use crate::{
 | 
				
			||||||
        common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics,
 | 
					        common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics,
 | 
				
			||||||
        ParsedType, SplitForImpl, TypesParser, WrappedInConst,
 | 
					        ParsedType, SplitForImpl, TypesParser, WrappedInConst,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    Errors, HdlAttr, PairsIterExt,
 | 
					    kw, Errors, HdlAttr, PairsIterExt,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use proc_macro2::TokenStream;
 | 
					use proc_macro2::TokenStream;
 | 
				
			||||||
use quote::{format_ident, quote_spanned, ToTokens};
 | 
					use quote::{format_ident, quote_spanned, ToTokens};
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ crate::options! {
 | 
				
			||||||
pub(crate) struct ParsedVariantField {
 | 
					pub(crate) struct ParsedVariantField {
 | 
				
			||||||
    pub(crate) paren_token: Paren,
 | 
					    pub(crate) paren_token: Paren,
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    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) ty: MaybeParsed<ParsedType, Type>,
 | 
				
			||||||
    pub(crate) comma_token: Option<Token![,]>,
 | 
					    pub(crate) comma_token: Option<Token![,]>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ pub(crate) struct ParsedVariantField {
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub(crate) struct ParsedVariant {
 | 
					pub(crate) struct ParsedVariant {
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
    pub(crate) options: HdlAttr<VariantOptions>,
 | 
					    pub(crate) options: HdlAttr<VariantOptions, kw::hdl>,
 | 
				
			||||||
    pub(crate) ident: Ident,
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
    pub(crate) field: Option<ParsedVariantField>,
 | 
					    pub(crate) field: Option<ParsedVariantField>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,7 @@ impl ParsedVariant {
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub(crate) struct ParsedEnum {
 | 
					pub(crate) struct ParsedEnum {
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
    pub(crate) options: HdlAttr<ItemOptions>,
 | 
					    pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
 | 
				
			||||||
    pub(crate) vis: Visibility,
 | 
					    pub(crate) vis: Visibility,
 | 
				
			||||||
    pub(crate) enum_token: Token![enum],
 | 
					    pub(crate) enum_token: Token![enum],
 | 
				
			||||||
    pub(crate) ident: Ident,
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
| 
						 | 
					@ -142,7 +142,9 @@ impl ParsedEnum {
 | 
				
			||||||
        } = item;
 | 
					        } = item;
 | 
				
			||||||
        let mut errors = Errors::new();
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
        let mut options = errors
 | 
					        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();
 | 
					            .unwrap_or_default();
 | 
				
			||||||
        errors.ok(options.body.validate());
 | 
					        errors.ok(options.body.validate());
 | 
				
			||||||
        let ItemOptions {
 | 
					        let ItemOptions {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1745,7 +1745,7 @@ impl<T: ParseTypes<I>, I, P: Clone> ParseTypes<Punctuated<I, P>> for Punctuated<
 | 
				
			||||||
pub(crate) enum UnparsedGenericParam {
 | 
					pub(crate) enum UnparsedGenericParam {
 | 
				
			||||||
    Type {
 | 
					    Type {
 | 
				
			||||||
        attrs: Vec<Attribute>,
 | 
					        attrs: Vec<Attribute>,
 | 
				
			||||||
        options: HdlAttr<TypeParamOptions>,
 | 
					        options: HdlAttr<TypeParamOptions, kw::hdl>,
 | 
				
			||||||
        ident: Ident,
 | 
					        ident: Ident,
 | 
				
			||||||
        colon_token: Token![:],
 | 
					        colon_token: Token![:],
 | 
				
			||||||
        bounds: ParsedBounds,
 | 
					        bounds: ParsedBounds,
 | 
				
			||||||
| 
						 | 
					@ -1753,7 +1753,7 @@ pub(crate) enum UnparsedGenericParam {
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    Const {
 | 
					    Const {
 | 
				
			||||||
        attrs: Vec<Attribute>,
 | 
					        attrs: Vec<Attribute>,
 | 
				
			||||||
        options: HdlAttr<ConstParamOptions>,
 | 
					        options: HdlAttr<ConstParamOptions, kw::hdl>,
 | 
				
			||||||
        const_token: Token![const],
 | 
					        const_token: Token![const],
 | 
				
			||||||
        ident: Ident,
 | 
					        ident: Ident,
 | 
				
			||||||
        colon_token: Token![:],
 | 
					        colon_token: Token![:],
 | 
				
			||||||
| 
						 | 
					@ -2278,7 +2278,7 @@ impl ParsedBound {
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub(crate) struct ParsedTypeParam {
 | 
					pub(crate) struct ParsedTypeParam {
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
    pub(crate) options: HdlAttr<TypeParamOptions>,
 | 
					    pub(crate) options: HdlAttr<TypeParamOptions, kw::hdl>,
 | 
				
			||||||
    pub(crate) ident: Ident,
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
    pub(crate) colon_token: Token![:],
 | 
					    pub(crate) colon_token: Token![:],
 | 
				
			||||||
    pub(crate) bounds: ParsedTypeBounds,
 | 
					    pub(crate) bounds: ParsedTypeBounds,
 | 
				
			||||||
| 
						 | 
					@ -2312,7 +2312,7 @@ impl ToTokens for ParsedTypeParam {
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub(crate) struct ParsedSizeTypeParam {
 | 
					pub(crate) struct ParsedSizeTypeParam {
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
    pub(crate) options: HdlAttr<TypeParamOptions>,
 | 
					    pub(crate) options: HdlAttr<TypeParamOptions, kw::hdl>,
 | 
				
			||||||
    pub(crate) ident: Ident,
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
    pub(crate) colon_token: Token![:],
 | 
					    pub(crate) colon_token: Token![:],
 | 
				
			||||||
    pub(crate) bounds: ParsedSizeTypeBounds,
 | 
					    pub(crate) bounds: ParsedSizeTypeBounds,
 | 
				
			||||||
| 
						 | 
					@ -2356,7 +2356,7 @@ pub(crate) struct ParsedConstParamWhereBounds {
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub(crate) struct ParsedConstParam {
 | 
					pub(crate) struct ParsedConstParam {
 | 
				
			||||||
    pub(crate) attrs: Vec<Attribute>,
 | 
					    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) const_token: Token![const],
 | 
				
			||||||
    pub(crate) ident: Ident,
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
    pub(crate) colon_token: Token![:],
 | 
					    pub(crate) colon_token: Token![:],
 | 
				
			||||||
| 
						 | 
					@ -2413,7 +2413,7 @@ impl ParsedGenericParam {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone, Default)]
 | 
				
			||||||
pub(crate) struct ParsedGenerics {
 | 
					pub(crate) struct ParsedGenerics {
 | 
				
			||||||
    pub(crate) lt_token: Option<Token![<]>,
 | 
					    pub(crate) lt_token: Option<Token![<]>,
 | 
				
			||||||
    pub(crate) params: Punctuated<ParsedGenericParam, Token![,]>,
 | 
					    pub(crate) params: Punctuated<ParsedGenericParam, Token![,]>,
 | 
				
			||||||
| 
						 | 
					@ -2863,9 +2863,11 @@ impl ParsedGenerics {
 | 
				
			||||||
            let (input_param, punct) = input_param.into_tuple();
 | 
					            let (input_param, punct) = input_param.into_tuple();
 | 
				
			||||||
            let (unparsed_param, late_parsed_param) = match input_param {
 | 
					            let (unparsed_param, late_parsed_param) = match input_param {
 | 
				
			||||||
                GenericParam::Lifetime(param) => {
 | 
					                GenericParam::Lifetime(param) => {
 | 
				
			||||||
                    errors.unwrap_or_default(HdlAttr::<LifetimeParamOptions>::parse_and_take_attr(
 | 
					                    errors.unwrap_or_default(
 | 
				
			||||||
                        &mut param.attrs,
 | 
					                        HdlAttr::<LifetimeParamOptions, kw::hdl>::parse_and_take_attr(
 | 
				
			||||||
                    ));
 | 
					                            &mut param.attrs,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                    errors.error(param, "lifetime generics are not supported by #[hdl]");
 | 
					                    errors.error(param, "lifetime generics are not supported by #[hdl]");
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -2879,7 +2881,9 @@ impl ParsedGenerics {
 | 
				
			||||||
                }) => {
 | 
					                }) => {
 | 
				
			||||||
                    let span = ident.span();
 | 
					                    let span = ident.span();
 | 
				
			||||||
                    let options = errors
 | 
					                    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();
 | 
					                        .unwrap_or_default();
 | 
				
			||||||
                    let colon_token = colon_token.unwrap_or_else(|| Token);
 | 
					                    let colon_token = colon_token.unwrap_or_else(|| Token);
 | 
				
			||||||
                    if !bounds.is_empty() {
 | 
					                    if !bounds.is_empty() {
 | 
				
			||||||
| 
						 | 
					@ -2917,7 +2921,9 @@ impl ParsedGenerics {
 | 
				
			||||||
                    default,
 | 
					                    default,
 | 
				
			||||||
                }) => {
 | 
					                }) => {
 | 
				
			||||||
                    let options = errors
 | 
					                    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();
 | 
					                        .unwrap_or_default();
 | 
				
			||||||
                    if let Some(default) = default {
 | 
					                    if let Some(default) = default {
 | 
				
			||||||
                        let _ = eq_token;
 | 
					                        let _ = eq_token;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,8 @@ use syn::{
 | 
				
			||||||
    parse::{Parse, ParseStream, Parser},
 | 
					    parse::{Parse, ParseStream, Parser},
 | 
				
			||||||
    parse_quote,
 | 
					    parse_quote,
 | 
				
			||||||
    punctuated::Pair,
 | 
					    punctuated::Pair,
 | 
				
			||||||
    AttrStyle, Attribute, Error, Item, Token,
 | 
					    spanned::Spanned,
 | 
				
			||||||
 | 
					    AttrStyle, Attribute, Error, Item, ItemFn, Token,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod fold;
 | 
					mod fold;
 | 
				
			||||||
| 
						 | 
					@ -17,8 +18,20 @@ mod hdl_bundle;
 | 
				
			||||||
mod hdl_enum;
 | 
					mod hdl_enum;
 | 
				
			||||||
mod hdl_type_common;
 | 
					mod hdl_type_common;
 | 
				
			||||||
mod module;
 | 
					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 {
 | 
					mod kw {
 | 
				
			||||||
    pub(crate) use syn::token::Extern as extern_;
 | 
					    pub(crate) use syn::token::Extern as extern_;
 | 
				
			||||||
| 
						 | 
					@ -38,6 +51,10 @@ mod kw {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            crate::fold::no_op_fold!($kw);
 | 
					            crate::fold::no_op_fold!($kw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            impl crate::CustomToken for $kw {
 | 
				
			||||||
 | 
					                const IDENT_STR: &'static str = stringify!($kw);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +63,9 @@ mod kw {
 | 
				
			||||||
    custom_keyword!(custom_bounds);
 | 
					    custom_keyword!(custom_bounds);
 | 
				
			||||||
    custom_keyword!(flip);
 | 
					    custom_keyword!(flip);
 | 
				
			||||||
    custom_keyword!(hdl);
 | 
					    custom_keyword!(hdl);
 | 
				
			||||||
 | 
					    custom_keyword!(hdl_module);
 | 
				
			||||||
    custom_keyword!(input);
 | 
					    custom_keyword!(input);
 | 
				
			||||||
 | 
					    custom_keyword!(incomplete_wire);
 | 
				
			||||||
    custom_keyword!(instance);
 | 
					    custom_keyword!(instance);
 | 
				
			||||||
    custom_keyword!(m);
 | 
					    custom_keyword!(m);
 | 
				
			||||||
    custom_keyword!(memory);
 | 
					    custom_keyword!(memory);
 | 
				
			||||||
| 
						 | 
					@ -68,34 +87,34 @@ mod kw {
 | 
				
			||||||
type Pound = Token![#]; // work around https://github.com/rust-lang/rust/issues/50676
 | 
					type Pound = Token![#]; // work around https://github.com/rust-lang/rust/issues/50676
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub(crate) struct HdlAttr<T> {
 | 
					pub(crate) struct HdlAttr<T, KW> {
 | 
				
			||||||
    pub(crate) pound_token: Pound,
 | 
					    pub(crate) pound_token: Pound,
 | 
				
			||||||
    pub(crate) style: AttrStyle,
 | 
					    pub(crate) style: AttrStyle,
 | 
				
			||||||
    pub(crate) bracket_token: syn::token::Bracket,
 | 
					    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) paren_token: Option<syn::token::Paren>,
 | 
				
			||||||
    pub(crate) body: T,
 | 
					    pub(crate) body: T,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
crate::fold::impl_fold! {
 | 
					crate::fold::impl_fold! {
 | 
				
			||||||
    struct HdlAttr<T,> {
 | 
					    struct HdlAttr<T, KW,> {
 | 
				
			||||||
        pound_token: Pound,
 | 
					        pound_token: Pound,
 | 
				
			||||||
        style: AttrStyle,
 | 
					        style: AttrStyle,
 | 
				
			||||||
        bracket_token: syn::token::Bracket,
 | 
					        bracket_token: syn::token::Bracket,
 | 
				
			||||||
        hdl: kw::hdl,
 | 
					        kw: KW,
 | 
				
			||||||
        paren_token: Option<syn::token::Paren>,
 | 
					        paren_token: Option<syn::token::Paren>,
 | 
				
			||||||
        body: T,
 | 
					        body: T,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(dead_code)]
 | 
					#[allow(dead_code)]
 | 
				
			||||||
impl<T> HdlAttr<T> {
 | 
					impl<T, KW> HdlAttr<T, KW> {
 | 
				
			||||||
    pub(crate) fn split_body(self) -> (HdlAttr<()>, T) {
 | 
					    pub(crate) fn split_body(self) -> (HdlAttr<(), KW>, T) {
 | 
				
			||||||
        let Self {
 | 
					        let Self {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body,
 | 
					            body,
 | 
				
			||||||
        } = self;
 | 
					        } = self;
 | 
				
			||||||
| 
						 | 
					@ -104,19 +123,19 @@ impl<T> HdlAttr<T> {
 | 
				
			||||||
                pound_token,
 | 
					                pound_token,
 | 
				
			||||||
                style,
 | 
					                style,
 | 
				
			||||||
                bracket_token,
 | 
					                bracket_token,
 | 
				
			||||||
                hdl,
 | 
					                kw,
 | 
				
			||||||
                paren_token,
 | 
					                paren_token,
 | 
				
			||||||
                body: (),
 | 
					                body: (),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            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 {
 | 
					        let Self {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body: _,
 | 
					            body: _,
 | 
				
			||||||
        } = self;
 | 
					        } = self;
 | 
				
			||||||
| 
						 | 
					@ -124,17 +143,20 @@ impl<T> HdlAttr<T> {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body,
 | 
					            body,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub(crate) fn as_ref(&self) -> HdlAttr<&T> {
 | 
					    pub(crate) fn as_ref(&self) -> HdlAttr<&T, KW>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        KW: Clone,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        let Self {
 | 
					        let Self {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            ref kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            ref body,
 | 
					            ref body,
 | 
				
			||||||
        } = *self;
 | 
					        } = *self;
 | 
				
			||||||
| 
						 | 
					@ -142,17 +164,20 @@ impl<T> HdlAttr<T> {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw: kw.clone(),
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body,
 | 
					            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 {
 | 
					        let Self {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body,
 | 
					            body,
 | 
				
			||||||
        } = self;
 | 
					        } = self;
 | 
				
			||||||
| 
						 | 
					@ -160,17 +185,17 @@ impl<T> HdlAttr<T> {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body: f(body)?,
 | 
					            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 {
 | 
					        let Self {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body,
 | 
					            body,
 | 
				
			||||||
        } = self;
 | 
					        } = self;
 | 
				
			||||||
| 
						 | 
					@ -178,7 +203,7 @@ impl<T> HdlAttr<T> {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body: f(body),
 | 
					            body: f(body),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -186,31 +211,32 @@ impl<T> HdlAttr<T> {
 | 
				
			||||||
    fn to_attr(&self) -> Attribute
 | 
					    fn to_attr(&self) -> Attribute
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        T: ToTokens,
 | 
					        T: ToTokens,
 | 
				
			||||||
 | 
					        KW: ToTokens,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        parse_quote! { #self }
 | 
					        parse_quote! { #self }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Default> Default for HdlAttr<T> {
 | 
					impl<T: Default, KW: Default> Default for HdlAttr<T, KW> {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        T::default().into()
 | 
					        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 {
 | 
					    fn from(body: T) -> Self {
 | 
				
			||||||
        HdlAttr {
 | 
					        HdlAttr {
 | 
				
			||||||
            pound_token: Default::default(),
 | 
					            pound_token: Default::default(),
 | 
				
			||||||
            style: AttrStyle::Outer,
 | 
					            style: AttrStyle::Outer,
 | 
				
			||||||
            bracket_token: Default::default(),
 | 
					            bracket_token: Default::default(),
 | 
				
			||||||
            hdl: Default::default(),
 | 
					            kw: Default::default(),
 | 
				
			||||||
            paren_token: Default::default(),
 | 
					            paren_token: Default::default(),
 | 
				
			||||||
            body,
 | 
					            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) {
 | 
					    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
        self.pound_token.to_tokens(tokens);
 | 
					        self.pound_token.to_tokens(tokens);
 | 
				
			||||||
        match self.style {
 | 
					        match self.style {
 | 
				
			||||||
| 
						 | 
					@ -218,7 +244,7 @@ impl<T: ToTokens> ToTokens for HdlAttr<T> {
 | 
				
			||||||
            AttrStyle::Outer => {}
 | 
					            AttrStyle::Outer => {}
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        self.bracket_token.surround(tokens, |tokens| {
 | 
					        self.bracket_token.surround(tokens, |tokens| {
 | 
				
			||||||
            self.hdl.to_tokens(tokens);
 | 
					            self.kw.to_tokens(tokens);
 | 
				
			||||||
            match self.paren_token {
 | 
					            match self.paren_token {
 | 
				
			||||||
                Some(paren_token) => {
 | 
					                Some(paren_token) => {
 | 
				
			||||||
                    paren_token.surround(tokens, |tokens| self.body.to_tokens(tokens))
 | 
					                    paren_token.surround(tokens, |tokens| self.body.to_tokens(tokens))
 | 
				
			||||||
| 
						 | 
					@ -226,7 +252,7 @@ impl<T: ToTokens> ToTokens for HdlAttr<T> {
 | 
				
			||||||
                None => {
 | 
					                None => {
 | 
				
			||||||
                    let body = self.body.to_token_stream();
 | 
					                    let body = self.body.to_token_stream();
 | 
				
			||||||
                    if !body.is_empty() {
 | 
					                    if !body.is_empty() {
 | 
				
			||||||
                        syn::token::Paren(self.hdl.span)
 | 
					                        syn::token::Paren(self.kw.span())
 | 
				
			||||||
                            .surround(tokens, |tokens| tokens.extend([body]));
 | 
					                            .surround(tokens, |tokens| tokens.extend([body]));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -235,18 +261,24 @@ impl<T: ToTokens> ToTokens for HdlAttr<T> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn is_hdl_attr(attr: &Attribute) -> bool {
 | 
					fn is_hdl_attr<KW: CustomToken>(attr: &Attribute) -> bool {
 | 
				
			||||||
    attr.path().is_ident("hdl")
 | 
					    attr.path().is_ident(KW::IDENT_STR)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Parse> HdlAttr<T> {
 | 
					impl<T: Parse, KW: Parse> HdlAttr<T, KW> {
 | 
				
			||||||
    fn parse_and_take_attr(attrs: &mut Vec<Attribute>) -> syn::Result<Option<Self>> {
 | 
					    fn parse_and_take_attr(attrs: &mut Vec<Attribute>) -> syn::Result<Option<Self>>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        KW: ToTokens,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        let mut retval = None;
 | 
					        let mut retval = None;
 | 
				
			||||||
        let mut errors = Errors::new();
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
        attrs.retain(|attr| {
 | 
					        attrs.retain(|attr| {
 | 
				
			||||||
            if is_hdl_attr(attr) {
 | 
					            if let Ok(kw) = syn::parse2::<KW>(attr.path().to_token_stream()) {
 | 
				
			||||||
                if retval.is_some() {
 | 
					                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)));
 | 
					                errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v)));
 | 
				
			||||||
                false
 | 
					                false
 | 
				
			||||||
| 
						 | 
					@ -257,13 +289,19 @@ impl<T: Parse> HdlAttr<T> {
 | 
				
			||||||
        errors.finish()?;
 | 
					        errors.finish()?;
 | 
				
			||||||
        Ok(retval)
 | 
					        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 retval = None;
 | 
				
			||||||
        let mut errors = Errors::new();
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
        for attr in attrs {
 | 
					        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() {
 | 
					                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)));
 | 
					                errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v)));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -284,7 +322,7 @@ impl<T: Parse> HdlAttr<T> {
 | 
				
			||||||
    ) -> syn::Result<Self> {
 | 
					    ) -> syn::Result<Self> {
 | 
				
			||||||
        let bracket_content;
 | 
					        let bracket_content;
 | 
				
			||||||
        let bracket_token = bracketed!(bracket_content in input);
 | 
					        let bracket_token = bracketed!(bracket_content in input);
 | 
				
			||||||
        let hdl = bracket_content.parse()?;
 | 
					        let kw = bracket_content.parse()?;
 | 
				
			||||||
        let paren_content;
 | 
					        let paren_content;
 | 
				
			||||||
        let body;
 | 
					        let body;
 | 
				
			||||||
        let paren_token;
 | 
					        let paren_token;
 | 
				
			||||||
| 
						 | 
					@ -305,7 +343,7 @@ impl<T: Parse> HdlAttr<T> {
 | 
				
			||||||
            pound_token,
 | 
					            pound_token,
 | 
				
			||||||
            style,
 | 
					            style,
 | 
				
			||||||
            bracket_token,
 | 
					            bracket_token,
 | 
				
			||||||
            hdl,
 | 
					            kw,
 | 
				
			||||||
            paren_token,
 | 
					            paren_token,
 | 
				
			||||||
            body,
 | 
					            body,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
| 
						 | 
					@ -852,25 +890,31 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
 | 
					fn hdl_module_impl(item: ItemFn) -> syn::Result<TokenStream> {
 | 
				
			||||||
    let options = syn::parse2::<module::ConfigOptions>(attr)?;
 | 
					    let func = module::ModuleFn::parse_from_fn(item)?;
 | 
				
			||||||
    let options = HdlAttr::from(options);
 | 
					    let options = func.config_options();
 | 
				
			||||||
    let func = syn::parse2::<module::ModuleFn>(quote! { #options #item })?;
 | 
					 | 
				
			||||||
    let mut contents = func.generate();
 | 
					    let mut contents = func.generate();
 | 
				
			||||||
    if options.body.outline_generated.is_some() {
 | 
					    if options.outline_generated.is_some() {
 | 
				
			||||||
        contents = outline_generated(contents, "module-");
 | 
					        contents = outline_generated(contents, "module-");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Ok(contents)
 | 
					    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> {
 | 
					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 {
 | 
					    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),
 | 
				
			||||||
        _ => Err(syn::Error::new(
 | 
					        _ => Err(syn::Error::new(
 | 
				
			||||||
            Span::call_site(),
 | 
					            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
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    hdl_type_common::{ParsedGenerics, SplitForImpl},
 | 
					    hdl_type_common::{ParsedGenerics, SplitForImpl},
 | 
				
			||||||
 | 
					    kw,
 | 
				
			||||||
    module::transform_body::{HdlLet, HdlLetKindIO},
 | 
					    module::transform_body::{HdlLet, HdlLetKindIO},
 | 
				
			||||||
    options, Errors, HdlAttr, PairsIterExt,
 | 
					    options, Errors, HdlAttr, PairsIterExt,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -9,7 +10,6 @@ use proc_macro2::TokenStream;
 | 
				
			||||||
use quote::{format_ident, quote, quote_spanned, ToTokens};
 | 
					use quote::{format_ident, quote, quote_spanned, ToTokens};
 | 
				
			||||||
use std::collections::HashSet;
 | 
					use std::collections::HashSet;
 | 
				
			||||||
use syn::{
 | 
					use syn::{
 | 
				
			||||||
    parse::{Parse, ParseStream},
 | 
					 | 
				
			||||||
    parse_quote,
 | 
					    parse_quote,
 | 
				
			||||||
    visit::{visit_pat, Visit},
 | 
					    visit::{visit_pat, Visit},
 | 
				
			||||||
    Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct,
 | 
					    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) type ModuleIO = HdlLet<HdlLetKindIO>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) struct ModuleFn {
 | 
					struct ModuleFnModule {
 | 
				
			||||||
    attrs: Vec<Attribute>,
 | 
					    attrs: Vec<Attribute>,
 | 
				
			||||||
    config_options: HdlAttr<ConfigOptions>,
 | 
					    config_options: HdlAttr<ConfigOptions, kw::hdl_module>,
 | 
				
			||||||
    module_kind: ModuleKind,
 | 
					    module_kind: ModuleKind,
 | 
				
			||||||
    vis: Visibility,
 | 
					    vis: Visibility,
 | 
				
			||||||
    sig: Signature,
 | 
					    sig: Signature,
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,26 @@ pub(crate) struct ModuleFn {
 | 
				
			||||||
    the_struct: TokenStream,
 | 
					    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)]
 | 
					#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 | 
				
			||||||
pub(crate) enum ModuleKind {
 | 
					pub(crate) enum ModuleKind {
 | 
				
			||||||
    Extern,
 | 
					    Extern,
 | 
				
			||||||
| 
						 | 
					@ -89,14 +109,25 @@ impl Visit<'_> for ContainsSkippedIdent<'_> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Parse for ModuleFn {
 | 
					impl ModuleFn {
 | 
				
			||||||
    fn parse(input: ParseStream) -> syn::Result<Self> {
 | 
					    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 {
 | 
					        let ItemFn {
 | 
				
			||||||
            mut attrs,
 | 
					            mut attrs,
 | 
				
			||||||
            vis,
 | 
					            vis,
 | 
				
			||||||
            mut sig,
 | 
					            mut sig,
 | 
				
			||||||
            block,
 | 
					            block,
 | 
				
			||||||
        } = input.parse()?;
 | 
					        } = item;
 | 
				
			||||||
        let Signature {
 | 
					        let Signature {
 | 
				
			||||||
            ref constness,
 | 
					            ref constness,
 | 
				
			||||||
            ref asyncness,
 | 
					            ref asyncness,
 | 
				
			||||||
| 
						 | 
					@ -111,43 +142,60 @@ impl Parse for ModuleFn {
 | 
				
			||||||
            ref output,
 | 
					            ref output,
 | 
				
			||||||
        } = sig;
 | 
					        } = sig;
 | 
				
			||||||
        let mut errors = Errors::new();
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
        let config_options = errors
 | 
					        let Some(mut config_options) =
 | 
				
			||||||
            .unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs))
 | 
					            errors.unwrap_or_default(
 | 
				
			||||||
            .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 {
 | 
					        let ConfigOptions {
 | 
				
			||||||
            outline_generated: _,
 | 
					            outline_generated: _,
 | 
				
			||||||
            extern_,
 | 
					            extern_,
 | 
				
			||||||
        } = config_options.body;
 | 
					        } = config_options.body;
 | 
				
			||||||
        let module_kind = match extern_ {
 | 
					        let module_kind = match (config_options.kw, extern_) {
 | 
				
			||||||
            Some(_) => ModuleKind::Extern,
 | 
					            (HdlOrHdlModule::Hdl(_), None) => None,
 | 
				
			||||||
            None => ModuleKind::Normal,
 | 
					            (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),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        for fn_arg in inputs {
 | 
					        if let HdlOrHdlModule::HdlModule(_) = config_options.kw {
 | 
				
			||||||
            match fn_arg {
 | 
					            for fn_arg in inputs {
 | 
				
			||||||
                FnArg::Receiver(_) => {
 | 
					                match fn_arg {
 | 
				
			||||||
                    errors.push(syn::Error::new_spanned(fn_arg, "self not allowed here"));
 | 
					                    FnArg::Receiver(_) => {
 | 
				
			||||||
                }
 | 
					                        errors.push(syn::Error::new_spanned(fn_arg, "self not allowed here"));
 | 
				
			||||||
                FnArg::Typed(fn_arg) => {
 | 
					                    }
 | 
				
			||||||
                    visit_pat(
 | 
					                    FnArg::Typed(fn_arg) => {
 | 
				
			||||||
                        &mut CheckNameConflictsWithModuleBuilderVisitor {
 | 
					                        visit_pat(
 | 
				
			||||||
                            errors: &mut errors,
 | 
					                            &mut CheckNameConflictsWithModuleBuilderVisitor {
 | 
				
			||||||
                        },
 | 
					                                errors: &mut errors,
 | 
				
			||||||
                        &fn_arg.pat,
 | 
					                            },
 | 
				
			||||||
                    );
 | 
					                            &fn_arg.pat,
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					            if let Some(constness) = constness {
 | 
				
			||||||
        if let Some(constness) = constness {
 | 
					                errors.push(syn::Error::new_spanned(constness, "const not allowed here"));
 | 
				
			||||||
            errors.push(syn::Error::new_spanned(constness, "const not allowed here"));
 | 
					            }
 | 
				
			||||||
        }
 | 
					            if let Some(asyncness) = asyncness {
 | 
				
			||||||
        if let Some(asyncness) = asyncness {
 | 
					                errors.push(syn::Error::new_spanned(asyncness, "async not allowed here"));
 | 
				
			||||||
            errors.push(syn::Error::new_spanned(asyncness, "async not allowed here"));
 | 
					            }
 | 
				
			||||||
        }
 | 
					            if let Some(unsafety) = unsafety {
 | 
				
			||||||
        if let Some(unsafety) = unsafety {
 | 
					                errors.push(syn::Error::new_spanned(unsafety, "unsafe not allowed here"));
 | 
				
			||||||
            errors.push(syn::Error::new_spanned(unsafety, "unsafe not allowed here"));
 | 
					            }
 | 
				
			||||||
        }
 | 
					            if let Some(abi) = abi {
 | 
				
			||||||
        if let Some(abi) = abi {
 | 
					                errors.push(syn::Error::new_spanned(abi, "extern not allowed here"));
 | 
				
			||||||
            errors.push(syn::Error::new_spanned(abi, "extern not allowed here"));
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let mut skipped_idents = HashSet::new();
 | 
					        let mut skipped_idents = HashSet::new();
 | 
				
			||||||
        let struct_generic_params = generics
 | 
					        let struct_generic_params = generics
 | 
				
			||||||
| 
						 | 
					@ -155,14 +203,17 @@ impl Parse for ModuleFn {
 | 
				
			||||||
            .pairs_mut()
 | 
					            .pairs_mut()
 | 
				
			||||||
            .filter_map_pair_value_mut(|v| match v {
 | 
					            .filter_map_pair_value_mut(|v| match v {
 | 
				
			||||||
                GenericParam::Lifetime(LifetimeParam { attrs, .. }) => {
 | 
					                GenericParam::Lifetime(LifetimeParam { attrs, .. }) => {
 | 
				
			||||||
                    errors
 | 
					                    errors.unwrap_or_default(
 | 
				
			||||||
                        .unwrap_or_default(HdlAttr::<crate::kw::skip>::parse_and_take_attr(attrs));
 | 
					                        HdlAttr::<crate::kw::skip, kw::hdl>::parse_and_take_attr(attrs),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                GenericParam::Type(TypeParam { attrs, ident, .. })
 | 
					                GenericParam::Type(TypeParam { attrs, ident, .. })
 | 
				
			||||||
                | GenericParam::Const(ConstParam { attrs, ident, .. }) => {
 | 
					                | GenericParam::Const(ConstParam { attrs, ident, .. }) => {
 | 
				
			||||||
                    if errors
 | 
					                    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()
 | 
					                        .is_some()
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        skipped_idents.insert(ident.clone());
 | 
					                        skipped_idents.insert(ident.clone());
 | 
				
			||||||
| 
						 | 
					@ -176,6 +227,7 @@ impl Parse for ModuleFn {
 | 
				
			||||||
        let struct_where_clause = generics
 | 
					        let struct_where_clause = generics
 | 
				
			||||||
            .where_clause
 | 
					            .where_clause
 | 
				
			||||||
            .as_mut()
 | 
					            .as_mut()
 | 
				
			||||||
 | 
					            .filter(|_| matches!(config_options.kw, HdlOrHdlModule::HdlModule(_)))
 | 
				
			||||||
            .map(|where_clause| WhereClause {
 | 
					            .map(|where_clause| WhereClause {
 | 
				
			||||||
                where_token: where_clause.where_token,
 | 
					                where_token: where_clause.where_token,
 | 
				
			||||||
                predicates: where_clause
 | 
					                predicates: where_clause
 | 
				
			||||||
| 
						 | 
					@ -198,22 +250,26 @@ impl Parse for ModuleFn {
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                    .collect(),
 | 
					                    .collect(),
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        let struct_generics = Generics {
 | 
					        let struct_generics = if let HdlOrHdlModule::HdlModule(_) = config_options.kw {
 | 
				
			||||||
            lt_token: generics.lt_token,
 | 
					            let mut struct_generics = Generics {
 | 
				
			||||||
            params: struct_generic_params,
 | 
					                lt_token: generics.lt_token,
 | 
				
			||||||
            gt_token: generics.gt_token,
 | 
					                params: struct_generic_params,
 | 
				
			||||||
            where_clause: struct_where_clause,
 | 
					                gt_token: generics.gt_token,
 | 
				
			||||||
 | 
					                where_clause: struct_where_clause,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if let Some(variadic) = variadic {
 | 
				
			||||||
 | 
					                errors.push(syn::Error::new_spanned(variadic, "... not allowed here"));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if !matches!(output, ReturnType::Default) {
 | 
				
			||||||
 | 
					                errors.push(syn::Error::new_spanned(
 | 
				
			||||||
 | 
					                    output,
 | 
				
			||||||
 | 
					                    "return type not allowed here",
 | 
				
			||||||
 | 
					                ));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errors.ok(ParsedGenerics::parse(&mut struct_generics))
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Some(ParsedGenerics::default())
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if let Some(variadic) = variadic {
 | 
					 | 
				
			||||||
            errors.push(syn::Error::new_spanned(variadic, "... not allowed here"));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if !matches!(output, ReturnType::Default) {
 | 
					 | 
				
			||||||
            errors.push(syn::Error::new_spanned(
 | 
					 | 
				
			||||||
                output,
 | 
					 | 
				
			||||||
                "return type not allowed here",
 | 
					 | 
				
			||||||
            ));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        let struct_generics = errors.ok(ParsedGenerics::parse(&mut { struct_generics }));
 | 
					 | 
				
			||||||
        let body_results = struct_generics.as_ref().and_then(|struct_generics| {
 | 
					        let body_results = struct_generics.as_ref().and_then(|struct_generics| {
 | 
				
			||||||
            errors.ok(transform_body::transform_body(
 | 
					            errors.ok(transform_body::transform_body(
 | 
				
			||||||
                module_kind,
 | 
					                module_kind,
 | 
				
			||||||
| 
						 | 
					@ -224,6 +280,47 @@ impl Parse for ModuleFn {
 | 
				
			||||||
        errors.finish()?;
 | 
					        errors.finish()?;
 | 
				
			||||||
        let struct_generics = struct_generics.unwrap();
 | 
					        let struct_generics = struct_generics.unwrap();
 | 
				
			||||||
        let (block, io) = body_results.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) =
 | 
					        let (_struct_impl_generics, _struct_type_generics, struct_where_clause) =
 | 
				
			||||||
            struct_generics.split_for_impl();
 | 
					            struct_generics.split_for_impl();
 | 
				
			||||||
        let struct_where_clause: Option<WhereClause> = parse_quote! { #struct_where_clause };
 | 
					        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)?;
 | 
					        let the_struct = crate::hdl_bundle::hdl_bundle(the_struct)?;
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self(ModuleFnImpl::Module(ModuleFnModule {
 | 
				
			||||||
            attrs,
 | 
					            attrs,
 | 
				
			||||||
            config_options,
 | 
					            config_options,
 | 
				
			||||||
            module_kind,
 | 
					            module_kind: module_kind.unwrap(),
 | 
				
			||||||
            vis,
 | 
					            vis,
 | 
				
			||||||
            sig,
 | 
					            sig,
 | 
				
			||||||
            block,
 | 
					            block,
 | 
				
			||||||
            struct_generics,
 | 
					            struct_generics,
 | 
				
			||||||
            the_struct,
 | 
					            the_struct,
 | 
				
			||||||
        })
 | 
					        })))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ModuleFn {
 | 
					impl ModuleFn {
 | 
				
			||||||
    pub(crate) fn generate(self) -> TokenStream {
 | 
					    pub(crate) fn generate(self) -> TokenStream {
 | 
				
			||||||
        let Self {
 | 
					        let ModuleFnModule {
 | 
				
			||||||
            attrs,
 | 
					            attrs,
 | 
				
			||||||
            config_options,
 | 
					            config_options,
 | 
				
			||||||
            module_kind,
 | 
					            module_kind,
 | 
				
			||||||
| 
						 | 
					@ -283,7 +380,28 @@ impl ModuleFn {
 | 
				
			||||||
            block,
 | 
					            block,
 | 
				
			||||||
            struct_generics,
 | 
					            struct_generics,
 | 
				
			||||||
            the_struct,
 | 
					            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 {
 | 
					        let ConfigOptions {
 | 
				
			||||||
            outline_generated: _,
 | 
					            outline_generated: _,
 | 
				
			||||||
            extern_: _,
 | 
					            extern_: _,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,7 @@ options! {
 | 
				
			||||||
        Instance(instance),
 | 
					        Instance(instance),
 | 
				
			||||||
        RegBuilder(reg_builder),
 | 
					        RegBuilder(reg_builder),
 | 
				
			||||||
        Wire(wire),
 | 
					        Wire(wire),
 | 
				
			||||||
 | 
					        IncompleteWire(incomplete_wire),
 | 
				
			||||||
        Memory(memory),
 | 
					        Memory(memory),
 | 
				
			||||||
        MemoryArray(memory_array),
 | 
					        MemoryArray(memory_array),
 | 
				
			||||||
        MemoryWithInit(memory_with_init),
 | 
					        MemoryWithInit(memory_with_init),
 | 
				
			||||||
| 
						 | 
					@ -533,6 +534,41 @@ impl HdlLetKindToTokens for HdlLetKindWire {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					options! {
 | 
				
			||||||
 | 
					    pub(crate) enum LetFnKindIncomplete {
 | 
				
			||||||
 | 
					        IncompleteWire(incomplete_wire),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					pub(crate) struct HdlLetKindIncomplete {
 | 
				
			||||||
 | 
					    pub(crate) kind: LetFnKindIncomplete,
 | 
				
			||||||
 | 
					    pub(crate) paren: Paren,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ParseTypes<Self> for HdlLetKindIncomplete {
 | 
				
			||||||
 | 
					    fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
 | 
				
			||||||
 | 
					        Ok(input.clone())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl_fold! {
 | 
				
			||||||
 | 
					    struct HdlLetKindIncomplete<> {
 | 
				
			||||||
 | 
					        kind: LetFnKindIncomplete,
 | 
				
			||||||
 | 
					        paren: Paren,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl HdlLetKindToTokens for HdlLetKindIncomplete {
 | 
				
			||||||
 | 
					    fn ty_to_tokens(&self, _tokens: &mut TokenStream) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn expr_to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
 | 
					        let Self { kind, paren } = self;
 | 
				
			||||||
 | 
					        kind.to_tokens(tokens);
 | 
				
			||||||
 | 
					        paren.surround(tokens, |_| {});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
options! {
 | 
					options! {
 | 
				
			||||||
    pub(crate) enum MemoryFnName {
 | 
					    pub(crate) enum MemoryFnName {
 | 
				
			||||||
        Memory(memory),
 | 
					        Memory(memory),
 | 
				
			||||||
| 
						 | 
					@ -697,6 +733,7 @@ impl HdlLetKindMemory {
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub(crate) enum HdlLetKind<IOType = ParsedType> {
 | 
					pub(crate) enum HdlLetKind<IOType = ParsedType> {
 | 
				
			||||||
    IO(HdlLetKindIO<ModuleIOKind, IOType>),
 | 
					    IO(HdlLetKindIO<ModuleIOKind, IOType>),
 | 
				
			||||||
 | 
					    Incomplete(HdlLetKindIncomplete),
 | 
				
			||||||
    Instance(HdlLetKindInstance),
 | 
					    Instance(HdlLetKindInstance),
 | 
				
			||||||
    RegBuilder(HdlLetKindRegBuilder),
 | 
					    RegBuilder(HdlLetKindRegBuilder),
 | 
				
			||||||
    Wire(HdlLetKindWire),
 | 
					    Wire(HdlLetKindWire),
 | 
				
			||||||
| 
						 | 
					@ -706,6 +743,7 @@ pub(crate) enum HdlLetKind<IOType = ParsedType> {
 | 
				
			||||||
impl_fold! {
 | 
					impl_fold! {
 | 
				
			||||||
    enum HdlLetKind<IOType,> {
 | 
					    enum HdlLetKind<IOType,> {
 | 
				
			||||||
        IO(HdlLetKindIO<ModuleIOKind, IOType>),
 | 
					        IO(HdlLetKindIO<ModuleIOKind, IOType>),
 | 
				
			||||||
 | 
					        Incomplete(HdlLetKindIncomplete),
 | 
				
			||||||
        Instance(HdlLetKindInstance),
 | 
					        Instance(HdlLetKindInstance),
 | 
				
			||||||
        RegBuilder(HdlLetKindRegBuilder),
 | 
					        RegBuilder(HdlLetKindRegBuilder),
 | 
				
			||||||
        Wire(HdlLetKindWire),
 | 
					        Wire(HdlLetKindWire),
 | 
				
			||||||
| 
						 | 
					@ -720,6 +758,9 @@ impl<T: ParseTypes<I>, I> ParseTypes<HdlLetKind<I>> for HdlLetKind<T> {
 | 
				
			||||||
    ) -> Result<Self, ParseFailed> {
 | 
					    ) -> Result<Self, ParseFailed> {
 | 
				
			||||||
        match input {
 | 
					        match input {
 | 
				
			||||||
            HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO),
 | 
					            HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO),
 | 
				
			||||||
 | 
					            HdlLetKind::Incomplete(input) => {
 | 
				
			||||||
 | 
					                ParseTypes::parse_types(input, parser).map(HdlLetKind::Incomplete)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            HdlLetKind::Instance(input) => {
 | 
					            HdlLetKind::Instance(input) => {
 | 
				
			||||||
                ParseTypes::parse_types(input, parser).map(HdlLetKind::Instance)
 | 
					                ParseTypes::parse_types(input, parser).map(HdlLetKind::Instance)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -871,6 +912,20 @@ impl HdlLetKindParse for HdlLetKind<Type> {
 | 
				
			||||||
                    ty_expr: paren_contents.call(parse_optional_fn_arg)?,
 | 
					                    ty_expr: paren_contents.call(parse_optional_fn_arg)?,
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            LetFnKind::IncompleteWire(incomplete_wire) => {
 | 
				
			||||||
 | 
					                if let Some(parsed_ty) = parsed_ty {
 | 
				
			||||||
 | 
					                    return Err(Error::new_spanned(
 | 
				
			||||||
 | 
					                        parsed_ty.1,
 | 
				
			||||||
 | 
					                        "type annotation not allowed for incomplete_wire",
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                check_empty_m_dot(m_dot, kind)?;
 | 
				
			||||||
 | 
					                let _paren_contents;
 | 
				
			||||||
 | 
					                Ok(Self::Incomplete(HdlLetKindIncomplete {
 | 
				
			||||||
 | 
					                    kind: LetFnKindIncomplete::IncompleteWire(incomplete_wire),
 | 
				
			||||||
 | 
					                    paren: parenthesized!(_paren_contents in input),
 | 
				
			||||||
 | 
					                }))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            LetFnKind::Memory(fn_name) => HdlLetKindMemory::rest_of_parse(
 | 
					            LetFnKind::Memory(fn_name) => HdlLetKindMemory::rest_of_parse(
 | 
				
			||||||
                input,
 | 
					                input,
 | 
				
			||||||
                parsed_ty,
 | 
					                parsed_ty,
 | 
				
			||||||
| 
						 | 
					@ -903,6 +958,7 @@ impl HdlLetKindToTokens for HdlLetKind {
 | 
				
			||||||
    fn ty_to_tokens(&self, tokens: &mut TokenStream) {
 | 
					    fn ty_to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            HdlLetKind::IO(v) => v.ty_to_tokens(tokens),
 | 
					            HdlLetKind::IO(v) => v.ty_to_tokens(tokens),
 | 
				
			||||||
 | 
					            HdlLetKind::Incomplete(v) => v.ty_to_tokens(tokens),
 | 
				
			||||||
            HdlLetKind::Instance(v) => v.ty_to_tokens(tokens),
 | 
					            HdlLetKind::Instance(v) => v.ty_to_tokens(tokens),
 | 
				
			||||||
            HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens),
 | 
					            HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens),
 | 
				
			||||||
            HdlLetKind::Wire(v) => v.ty_to_tokens(tokens),
 | 
					            HdlLetKind::Wire(v) => v.ty_to_tokens(tokens),
 | 
				
			||||||
| 
						 | 
					@ -913,6 +969,7 @@ impl HdlLetKindToTokens for HdlLetKind {
 | 
				
			||||||
    fn expr_to_tokens(&self, tokens: &mut TokenStream) {
 | 
					    fn expr_to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            HdlLetKind::IO(v) => v.expr_to_tokens(tokens),
 | 
					            HdlLetKind::IO(v) => v.expr_to_tokens(tokens),
 | 
				
			||||||
 | 
					            HdlLetKind::Incomplete(v) => v.expr_to_tokens(tokens),
 | 
				
			||||||
            HdlLetKind::Instance(v) => v.expr_to_tokens(tokens),
 | 
					            HdlLetKind::Instance(v) => v.expr_to_tokens(tokens),
 | 
				
			||||||
            HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens),
 | 
					            HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens),
 | 
				
			||||||
            HdlLetKind::Wire(v) => v.expr_to_tokens(tokens),
 | 
					            HdlLetKind::Wire(v) => v.expr_to_tokens(tokens),
 | 
				
			||||||
| 
						 | 
					@ -925,7 +982,7 @@ with_debug_clone_and_fold! {
 | 
				
			||||||
    #[allow(dead_code)]
 | 
					    #[allow(dead_code)]
 | 
				
			||||||
    pub(crate) struct HdlLet<Kind = HdlLetKind> {
 | 
					    pub(crate) struct HdlLet<Kind = HdlLetKind> {
 | 
				
			||||||
        pub(crate) attrs: Vec<Attribute>,
 | 
					        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) let_token: Token![let],
 | 
				
			||||||
        pub(crate) mut_token: Option<Token![mut]>,
 | 
					        pub(crate) mut_token: Option<Token![mut]>,
 | 
				
			||||||
        pub(crate) name: Ident,
 | 
					        pub(crate) name: Ident,
 | 
				
			||||||
| 
						 | 
					@ -1112,7 +1169,7 @@ impl<T: ToString> ToTokens for ImplicitName<T> {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Visitor<'a> {
 | 
					struct Visitor<'a> {
 | 
				
			||||||
    module_kind: ModuleKind,
 | 
					    module_kind: Option<ModuleKind>,
 | 
				
			||||||
    errors: Errors,
 | 
					    errors: Errors,
 | 
				
			||||||
    io: Vec<ModuleIO>,
 | 
					    io: Vec<ModuleIO>,
 | 
				
			||||||
    block_depth: usize,
 | 
					    block_depth: usize,
 | 
				
			||||||
| 
						 | 
					@ -1120,22 +1177,33 @@ struct Visitor<'a> {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Visitor<'_> {
 | 
					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(
 | 
					        self.errors.unwrap_or(
 | 
				
			||||||
            HdlAttr::parse_and_take_attr(attrs),
 | 
					            HdlAttr::parse_and_take_attr(attrs),
 | 
				
			||||||
            Some(syn::parse2::<T>(quote! {}).unwrap().into()),
 | 
					            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 {
 | 
					        match self.module_kind {
 | 
				
			||||||
            ModuleKind::Extern => {
 | 
					            Some(ModuleKind::Extern) => {
 | 
				
			||||||
                self.errors
 | 
					                self.errors
 | 
				
			||||||
                    .error(spanned, "not allowed in #[hdl_module(extern)]");
 | 
					                    .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 {
 | 
					        let ExprIf {
 | 
				
			||||||
            attrs,
 | 
					            attrs,
 | 
				
			||||||
            if_token,
 | 
					            if_token,
 | 
				
			||||||
| 
						 | 
					@ -1143,7 +1211,7 @@ impl Visitor<'_> {
 | 
				
			||||||
            then_branch,
 | 
					            then_branch,
 | 
				
			||||||
            else_branch,
 | 
					            else_branch,
 | 
				
			||||||
        } = expr_if;
 | 
					        } = 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 {
 | 
					        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::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if),
 | 
				
			||||||
            expr => expr,
 | 
					            expr => expr,
 | 
				
			||||||
| 
						 | 
					@ -1208,11 +1276,12 @@ impl Visitor<'_> {
 | 
				
			||||||
            .to_tokens(expr);
 | 
					            .to_tokens(expr);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        let mut attrs = hdl_let.attrs.clone();
 | 
					        let mut attrs = hdl_let.attrs.clone();
 | 
				
			||||||
 | 
					        self.require_module(kind);
 | 
				
			||||||
        match self.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)]
 | 
					                #[allow(unused_variables)]
 | 
				
			||||||
            }),
 | 
					            }),
 | 
				
			||||||
            ModuleKind::Normal => {}
 | 
					            Some(ModuleKind::Normal) | None => {}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let let_stmt = Local {
 | 
					        let let_stmt = Local {
 | 
				
			||||||
            attrs,
 | 
					            attrs,
 | 
				
			||||||
| 
						 | 
					@ -1249,7 +1318,7 @@ impl Visitor<'_> {
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            semi_token,
 | 
					            semi_token,
 | 
				
			||||||
        } = hdl_let;
 | 
					        } = hdl_let;
 | 
				
			||||||
        self.require_normal_module(instance);
 | 
					        self.require_normal_module_or_fn(instance);
 | 
				
			||||||
        let mut expr = instance.to_token_stream();
 | 
					        let mut expr = instance.to_token_stream();
 | 
				
			||||||
        paren.surround(&mut expr, |expr| {
 | 
					        paren.surround(&mut expr, |expr| {
 | 
				
			||||||
            let name_str = ImplicitName {
 | 
					            let name_str = ImplicitName {
 | 
				
			||||||
| 
						 | 
					@ -1276,7 +1345,7 @@ impl Visitor<'_> {
 | 
				
			||||||
    fn process_hdl_let_reg_builder(&mut self, hdl_let: HdlLet<HdlLetKindRegBuilder>) -> Local {
 | 
					    fn process_hdl_let_reg_builder(&mut self, hdl_let: HdlLet<HdlLetKindRegBuilder>) -> Local {
 | 
				
			||||||
        let name = &hdl_let.name;
 | 
					        let name = &hdl_let.name;
 | 
				
			||||||
        let reg_builder = hdl_let.kind.reg_builder;
 | 
					        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();
 | 
					        let mut expr = reg_builder.to_token_stream();
 | 
				
			||||||
        hdl_let.kind.reg_builder_paren.surround(&mut expr, |expr| {
 | 
					        hdl_let.kind.reg_builder_paren.surround(&mut expr, |expr| {
 | 
				
			||||||
            let name_str = ImplicitName {
 | 
					            let name_str = ImplicitName {
 | 
				
			||||||
| 
						 | 
					@ -1327,7 +1396,7 @@ impl Visitor<'_> {
 | 
				
			||||||
    fn process_hdl_let_wire(&mut self, hdl_let: HdlLet<HdlLetKindWire>) -> Local {
 | 
					    fn process_hdl_let_wire(&mut self, hdl_let: HdlLet<HdlLetKindWire>) -> Local {
 | 
				
			||||||
        let name = &hdl_let.name;
 | 
					        let name = &hdl_let.name;
 | 
				
			||||||
        let wire = hdl_let.kind.wire;
 | 
					        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 ty_expr = unwrap_or_static_type(hdl_let.kind.ty_expr.as_ref(), wire.span());
 | 
				
			||||||
        let mut expr = wire.to_token_stream();
 | 
					        let mut expr = wire.to_token_stream();
 | 
				
			||||||
        hdl_let.kind.paren.surround(&mut expr, |expr| {
 | 
					        hdl_let.kind.paren.surround(&mut expr, |expr| {
 | 
				
			||||||
| 
						 | 
					@ -1357,11 +1426,36 @@ impl Visitor<'_> {
 | 
				
			||||||
            semi_token: hdl_let.semi_token,
 | 
					            semi_token: hdl_let.semi_token,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn process_hdl_let_incomplete(&mut self, hdl_let: HdlLet<HdlLetKindIncomplete>) -> Local {
 | 
				
			||||||
 | 
					        let name = &hdl_let.name;
 | 
				
			||||||
 | 
					        let kind = hdl_let.kind.kind;
 | 
				
			||||||
 | 
					        self.require_normal_module_or_fn(kind);
 | 
				
			||||||
 | 
					        let mut expr = kind.to_token_stream();
 | 
				
			||||||
 | 
					        hdl_let.kind.paren.surround(&mut expr, |expr| {
 | 
				
			||||||
 | 
					            ImplicitName {
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                span: name.span(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_tokens(expr);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let mut_token = &hdl_let.mut_token;
 | 
				
			||||||
 | 
					        Local {
 | 
				
			||||||
 | 
					            attrs: hdl_let.attrs.clone(),
 | 
				
			||||||
 | 
					            let_token: hdl_let.let_token,
 | 
				
			||||||
 | 
					            pat: parse_quote! { #mut_token #name },
 | 
				
			||||||
 | 
					            init: Some(LocalInit {
 | 
				
			||||||
 | 
					                eq_token: hdl_let.eq_token,
 | 
				
			||||||
 | 
					                expr: parse_quote! { #expr },
 | 
				
			||||||
 | 
					                diverge: None,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            semi_token: hdl_let.semi_token,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fn process_hdl_let_memory(&mut self, hdl_let: HdlLet<HdlLetKindMemory>) -> Local {
 | 
					    fn process_hdl_let_memory(&mut self, hdl_let: HdlLet<HdlLetKindMemory>) -> Local {
 | 
				
			||||||
        let name = &hdl_let.name;
 | 
					        let name = &hdl_let.name;
 | 
				
			||||||
        let memory_fn = hdl_let.kind.memory_fn;
 | 
					        let memory_fn = hdl_let.kind.memory_fn;
 | 
				
			||||||
        let memory_fn_name = memory_fn.name();
 | 
					        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 mut expr = memory_fn_name.to_token_stream();
 | 
				
			||||||
        let (paren, arg) = match memory_fn {
 | 
					        let (paren, arg) = match memory_fn {
 | 
				
			||||||
            MemoryFn::Memory {
 | 
					            MemoryFn::Memory {
 | 
				
			||||||
| 
						 | 
					@ -1426,6 +1520,7 @@ impl Visitor<'_> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        the_match! {
 | 
					        the_match! {
 | 
				
			||||||
            IO => process_hdl_let_io,
 | 
					            IO => process_hdl_let_io,
 | 
				
			||||||
 | 
					            Incomplete => process_hdl_let_incomplete,
 | 
				
			||||||
            Instance => process_hdl_let_instance,
 | 
					            Instance => process_hdl_let_instance,
 | 
				
			||||||
            RegBuilder => process_hdl_let_reg_builder,
 | 
					            RegBuilder => process_hdl_let_reg_builder,
 | 
				
			||||||
            Wire => process_hdl_let_wire,
 | 
					            Wire => process_hdl_let_wire,
 | 
				
			||||||
| 
						 | 
					@ -1543,7 +1638,7 @@ impl Fold for Visitor<'_> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_attribute(&mut self, attr: Attribute) -> Attribute {
 | 
					    fn fold_attribute(&mut self, attr: Attribute) -> Attribute {
 | 
				
			||||||
        if is_hdl_attr(&attr) {
 | 
					        if is_hdl_attr::<kw::hdl>(&attr) {
 | 
				
			||||||
            self.errors
 | 
					            self.errors
 | 
				
			||||||
                .error(&attr, "#[hdl] attribute not supported here");
 | 
					                .error(&attr, "#[hdl] attribute not supported here");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -1610,8 +1705,9 @@ impl Fold for Visitor<'_> {
 | 
				
			||||||
    fn fold_local(&mut self, let_stmt: Local) -> Local {
 | 
					    fn fold_local(&mut self, let_stmt: Local) -> Local {
 | 
				
			||||||
        match self
 | 
					        match self
 | 
				
			||||||
            .errors
 | 
					            .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(),
 | 
					            None => return empty_let(),
 | 
				
			||||||
            Some(None) => return fold_local(self, let_stmt),
 | 
					            Some(None) => return fold_local(self, let_stmt),
 | 
				
			||||||
            Some(Some(HdlAttr { .. })) => {}
 | 
					            Some(Some(HdlAttr { .. })) => {}
 | 
				
			||||||
| 
						 | 
					@ -1646,7 +1742,7 @@ impl Fold for Visitor<'_> {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) fn transform_body(
 | 
					pub(crate) fn transform_body(
 | 
				
			||||||
    module_kind: ModuleKind,
 | 
					    module_kind: Option<ModuleKind>,
 | 
				
			||||||
    mut body: Box<Block>,
 | 
					    mut body: Box<Block>,
 | 
				
			||||||
    parsed_generics: &ParsedGenerics,
 | 
					    parsed_generics: &ParsedGenerics,
 | 
				
			||||||
) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> {
 | 
					) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// 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 quote::{format_ident, quote_spanned};
 | 
				
			||||||
use syn::{
 | 
					use syn::{
 | 
				
			||||||
    parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
 | 
					    parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
 | 
				
			||||||
| 
						 | 
					@ -10,10 +10,10 @@ use syn::{
 | 
				
			||||||
impl Visitor<'_> {
 | 
					impl Visitor<'_> {
 | 
				
			||||||
    pub(crate) fn process_hdl_array(
 | 
					    pub(crate) fn process_hdl_array(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        hdl_attr: HdlAttr<Nothing>,
 | 
					        hdl_attr: HdlAttr<Nothing, kw::hdl>,
 | 
				
			||||||
        mut expr_array: ExprArray,
 | 
					        mut expr_array: ExprArray,
 | 
				
			||||||
    ) -> Expr {
 | 
					    ) -> Expr {
 | 
				
			||||||
        self.require_normal_module(hdl_attr);
 | 
					        self.require_normal_module_or_fn(hdl_attr);
 | 
				
			||||||
        for elem in &mut expr_array.elems {
 | 
					        for elem in &mut expr_array.elems {
 | 
				
			||||||
            *elem = parse_quote_spanned! {elem.span()=>
 | 
					            *elem = parse_quote_spanned! {elem.span()=>
 | 
				
			||||||
                ::fayalite::expr::ToExpr::to_expr(&(#elem))
 | 
					                ::fayalite::expr::ToExpr::to_expr(&(#elem))
 | 
				
			||||||
| 
						 | 
					@ -23,10 +23,10 @@ impl Visitor<'_> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub(crate) fn process_hdl_repeat(
 | 
					    pub(crate) fn process_hdl_repeat(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        hdl_attr: HdlAttr<Nothing>,
 | 
					        hdl_attr: HdlAttr<Nothing, kw::hdl>,
 | 
				
			||||||
        mut expr_repeat: ExprRepeat,
 | 
					        mut expr_repeat: ExprRepeat,
 | 
				
			||||||
    ) -> Expr {
 | 
					    ) -> Expr {
 | 
				
			||||||
        self.require_normal_module(hdl_attr);
 | 
					        self.require_normal_module_or_fn(hdl_attr);
 | 
				
			||||||
        let repeated_value = &expr_repeat.expr;
 | 
					        let repeated_value = &expr_repeat.expr;
 | 
				
			||||||
        *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
 | 
					        *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
 | 
				
			||||||
            ::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
 | 
					            ::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
 | 
				
			||||||
| 
						 | 
					@ -35,10 +35,10 @@ impl Visitor<'_> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub(crate) fn process_hdl_struct(
 | 
					    pub(crate) fn process_hdl_struct(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        hdl_attr: HdlAttr<Nothing>,
 | 
					        hdl_attr: HdlAttr<Nothing, kw::hdl>,
 | 
				
			||||||
        expr_struct: ExprStruct,
 | 
					        expr_struct: ExprStruct,
 | 
				
			||||||
    ) -> Expr {
 | 
					    ) -> 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 name_span = expr_struct.path.segments.last().unwrap().ident.span();
 | 
				
			||||||
        let builder_ident = format_ident!("__builder", span = name_span);
 | 
					        let builder_ident = format_ident!("__builder", span = name_span);
 | 
				
			||||||
        let empty_builder = if expr_struct.qself.is_some()
 | 
					        let empty_builder = if expr_struct.qself.is_some()
 | 
				
			||||||
| 
						 | 
					@ -91,10 +91,10 @@ impl Visitor<'_> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub(crate) fn process_hdl_tuple(
 | 
					    pub(crate) fn process_hdl_tuple(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        hdl_attr: HdlAttr<Nothing>,
 | 
					        hdl_attr: HdlAttr<Nothing, kw::hdl>,
 | 
				
			||||||
        expr_tuple: ExprTuple,
 | 
					        expr_tuple: ExprTuple,
 | 
				
			||||||
    ) -> Expr {
 | 
					    ) -> Expr {
 | 
				
			||||||
        self.require_normal_module(hdl_attr);
 | 
					        self.require_normal_module_or_fn(hdl_attr);
 | 
				
			||||||
        parse_quote_spanned! {expr_tuple.span()=>
 | 
					        parse_quote_spanned! {expr_tuple.span()=>
 | 
				
			||||||
            ::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
 | 
					            ::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    fold::{impl_fold, DoFold},
 | 
					    fold::{impl_fold, DoFold},
 | 
				
			||||||
 | 
					    kw,
 | 
				
			||||||
    module::transform_body::{with_debug_clone_and_fold, Visitor},
 | 
					    module::transform_body::{with_debug_clone_and_fold, Visitor},
 | 
				
			||||||
    Errors, HdlAttr, PairsIterExt,
 | 
					    Errors, HdlAttr, PairsIterExt,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -749,7 +750,7 @@ struct HdlMatchParseState<'a> {
 | 
				
			||||||
impl Visitor<'_> {
 | 
					impl Visitor<'_> {
 | 
				
			||||||
    pub(crate) fn process_hdl_match(
 | 
					    pub(crate) fn process_hdl_match(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        _hdl_attr: HdlAttr<Nothing>,
 | 
					        _hdl_attr: HdlAttr<Nothing, kw::hdl>,
 | 
				
			||||||
        expr_match: ExprMatch,
 | 
					        expr_match: ExprMatch,
 | 
				
			||||||
    ) -> Expr {
 | 
					    ) -> Expr {
 | 
				
			||||||
        let span = expr_match.match_token.span();
 | 
					        let span = expr_match.match_token.span();
 | 
				
			||||||
| 
						 | 
					@ -761,7 +762,7 @@ impl Visitor<'_> {
 | 
				
			||||||
            brace_token: _,
 | 
					            brace_token: _,
 | 
				
			||||||
            arms,
 | 
					            arms,
 | 
				
			||||||
        } = expr_match;
 | 
					        } = expr_match;
 | 
				
			||||||
        self.require_normal_module(match_token);
 | 
					        self.require_normal_module_or_fn(match_token);
 | 
				
			||||||
        let mut state = HdlMatchParseState {
 | 
					        let mut state = HdlMatchParseState {
 | 
				
			||||||
            match_span: span,
 | 
					            match_span: span,
 | 
				
			||||||
            errors: &mut self.errors,
 | 
					            errors: &mut self.errors,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,14 +7,14 @@ use crate::{
 | 
				
			||||||
    int::Bool,
 | 
					    int::Bool,
 | 
				
			||||||
    intern::{Intern, Interned},
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
    module::{
 | 
					    module::{
 | 
				
			||||||
        enum_match_variants_helper, EnumMatchVariantAndInactiveScopeImpl,
 | 
					        connect, enum_match_variants_helper, incomplete_wire, wire,
 | 
				
			||||||
        EnumMatchVariantsIterImpl, Scope,
 | 
					        EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{CanonicalType, MatchVariantAndInactiveScope, StaticType, Type, TypeProperties},
 | 
					    ty::{CanonicalType, MatchVariantAndInactiveScope, StaticType, Type, TypeProperties},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use hashbrown::HashMap;
 | 
					use hashbrown::HashMap;
 | 
				
			||||||
use std::{fmt, iter::FusedIterator};
 | 
					use std::{convert::Infallible, fmt, iter::FusedIterator};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
				
			||||||
pub struct EnumVariant {
 | 
					pub struct EnumVariant {
 | 
				
			||||||
| 
						 | 
					@ -364,3 +364,308 @@ pub fn HdlSome<T: Type>(value: impl ToExpr<Type = T>) -> Expr<HdlOption<T>> {
 | 
				
			||||||
    let value = value.to_expr();
 | 
					    let value = value.to_expr();
 | 
				
			||||||
    HdlOption[Expr::ty(value)].HdlSome(value)
 | 
					    HdlOption[Expr::ty(value)].HdlSome(value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Type> HdlOption<T> {
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn try_map<R: Type, E>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Result<Expr<R>, E>,
 | 
				
			||||||
 | 
					    ) -> Result<Expr<HdlOption<R>>, E> {
 | 
				
			||||||
 | 
					        Self::try_and_then(expr, |v| Ok(HdlSome(f(v)?)))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn map<R: Type>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Expr<R>,
 | 
				
			||||||
 | 
					    ) -> Expr<HdlOption<R>> {
 | 
				
			||||||
 | 
					        Self::and_then(expr, |v| HdlSome(f(v)))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn try_and_then<R: Type, E>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Result<Expr<HdlOption<R>>, E>,
 | 
				
			||||||
 | 
					    ) -> Result<Expr<HdlOption<R>>, E> {
 | 
				
			||||||
 | 
					        // manually run match steps so we can extract the return type to construct HdlNone
 | 
				
			||||||
 | 
					        type Wrap<T> = T;
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let mut and_then_out = incomplete_wire();
 | 
				
			||||||
 | 
					        let mut iter = Self::match_variants(expr, SourceLocation::caller());
 | 
				
			||||||
 | 
					        let none = iter.next().unwrap();
 | 
				
			||||||
 | 
					        let some = iter.next().unwrap();
 | 
				
			||||||
 | 
					        assert!(iter.next().is_none());
 | 
				
			||||||
 | 
					        let (Wrap::<<Self as Type>::MatchVariant>::HdlSome(value), some_scope) =
 | 
				
			||||||
 | 
					            Self::match_activate_scope(some)
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            unreachable!();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let value = f(value).map_err(|e| {
 | 
				
			||||||
 | 
					            and_then_out.complete(()); // avoid error
 | 
				
			||||||
 | 
					            e
 | 
				
			||||||
 | 
					        })?;
 | 
				
			||||||
 | 
					        let and_then_out = and_then_out.complete(Expr::ty(value));
 | 
				
			||||||
 | 
					        connect(and_then_out, value);
 | 
				
			||||||
 | 
					        drop(some_scope);
 | 
				
			||||||
 | 
					        let (Wrap::<<Self as Type>::MatchVariant>::HdlNone, none_scope) =
 | 
				
			||||||
 | 
					            Self::match_activate_scope(none)
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            unreachable!();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        connect(and_then_out, Expr::ty(and_then_out).HdlNone());
 | 
				
			||||||
 | 
					        drop(none_scope);
 | 
				
			||||||
 | 
					        Ok(and_then_out)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn and_then<R: Type>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Expr<HdlOption<R>>,
 | 
				
			||||||
 | 
					    ) -> Expr<HdlOption<R>> {
 | 
				
			||||||
 | 
					        match Self::try_and_then(expr, |v| Ok::<_, Infallible>(f(v))) {
 | 
				
			||||||
 | 
					            Ok(v) => v,
 | 
				
			||||||
 | 
					            Err(e) => match e {},
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn and<U: Type>(expr: Expr<Self>, opt_b: Expr<HdlOption<U>>) -> Expr<HdlOption<U>> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let and_out = wire(Expr::ty(opt_b));
 | 
				
			||||||
 | 
					        connect(and_out, Expr::ty(opt_b).HdlNone());
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(_) = expr {
 | 
				
			||||||
 | 
					            connect(and_out, opt_b);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        and_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn try_filter<E>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Result<Expr<Bool>, E>,
 | 
				
			||||||
 | 
					    ) -> Result<Expr<Self>, E> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let filtered = wire(Expr::ty(expr));
 | 
				
			||||||
 | 
					        connect(filtered, Expr::ty(expr).HdlNone());
 | 
				
			||||||
 | 
					        let mut f = Some(f);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(v) = expr {
 | 
				
			||||||
 | 
					            #[hdl]
 | 
				
			||||||
 | 
					            if f.take().unwrap()(v)? {
 | 
				
			||||||
 | 
					                connect(filtered, HdlSome(v));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(filtered)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn filter(expr: Expr<Self>, f: impl FnOnce(Expr<T>) -> Expr<Bool>) -> Expr<Self> {
 | 
				
			||||||
 | 
					        match Self::try_filter(expr, |v| Ok::<_, Infallible>(f(v))) {
 | 
				
			||||||
 | 
					            Ok(v) => v,
 | 
				
			||||||
 | 
					            Err(e) => match e {},
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn try_inspect<E>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Result<(), E>,
 | 
				
			||||||
 | 
					    ) -> Result<Expr<Self>, E> {
 | 
				
			||||||
 | 
					        let mut f = Some(f);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(v) = expr {
 | 
				
			||||||
 | 
					            f.take().unwrap()(v)?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(expr)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn inspect(expr: Expr<Self>, f: impl FnOnce(Expr<T>)) -> Expr<Self> {
 | 
				
			||||||
 | 
					        let mut f = Some(f);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(v) = expr {
 | 
				
			||||||
 | 
					            f.take().unwrap()(v);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        expr
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn is_none(expr: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let is_none_out: Bool = wire();
 | 
				
			||||||
 | 
					        connect(is_none_out, false);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlNone = expr {
 | 
				
			||||||
 | 
					            connect(is_none_out, true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        is_none_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn is_some(expr: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let is_some_out: Bool = wire();
 | 
				
			||||||
 | 
					        connect(is_some_out, false);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(_) = expr {
 | 
				
			||||||
 | 
					            connect(is_some_out, true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        is_some_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn map_or<R: Type>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        default: Expr<R>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Expr<R>,
 | 
				
			||||||
 | 
					    ) -> Expr<R> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let mapped = wire(Expr::ty(default));
 | 
				
			||||||
 | 
					        let mut f = Some(f);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        match expr {
 | 
				
			||||||
 | 
					            HdlSome(v) => connect(mapped, f.take().unwrap()(v)),
 | 
				
			||||||
 | 
					            HdlNone => connect(mapped, default),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        mapped
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn map_or_else<R: Type>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        default: impl FnOnce() -> Expr<R>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Expr<R>,
 | 
				
			||||||
 | 
					    ) -> Expr<R> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let mut mapped = incomplete_wire();
 | 
				
			||||||
 | 
					        let mut default = Some(default);
 | 
				
			||||||
 | 
					        let mut f = Some(f);
 | 
				
			||||||
 | 
					        let mut retval = None;
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        match expr {
 | 
				
			||||||
 | 
					            HdlSome(v) => {
 | 
				
			||||||
 | 
					                let v = f.take().unwrap()(v);
 | 
				
			||||||
 | 
					                let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v)));
 | 
				
			||||||
 | 
					                connect(mapped, v);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            HdlNone => {
 | 
				
			||||||
 | 
					                let v = default.take().unwrap()();
 | 
				
			||||||
 | 
					                let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v)));
 | 
				
			||||||
 | 
					                connect(mapped, v);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        retval.unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn or(expr: Expr<Self>, opt_b: Expr<Self>) -> Expr<Self> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let or_out = wire(Expr::ty(expr));
 | 
				
			||||||
 | 
					        connect(or_out, opt_b);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(_) = expr {
 | 
				
			||||||
 | 
					            connect(or_out, expr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        or_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn or_else(expr: Expr<Self>, f: impl FnOnce() -> Expr<Self>) -> Expr<Self> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let or_else_out = wire(Expr::ty(expr));
 | 
				
			||||||
 | 
					        connect(or_else_out, f());
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(_) = expr {
 | 
				
			||||||
 | 
					            connect(or_else_out, expr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        or_else_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn unwrap_or(expr: Expr<Self>, default: Expr<T>) -> Expr<T> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let unwrap_or_else_out = wire(Expr::ty(default));
 | 
				
			||||||
 | 
					        connect(unwrap_or_else_out, default);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(v) = expr {
 | 
				
			||||||
 | 
					            connect(unwrap_or_else_out, v);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        unwrap_or_else_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn unwrap_or_else(expr: Expr<Self>, f: impl FnOnce() -> Expr<T>) -> Expr<T> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let unwrap_or_else_out = wire(Expr::ty(expr).HdlSome);
 | 
				
			||||||
 | 
					        connect(unwrap_or_else_out, f());
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(v) = expr {
 | 
				
			||||||
 | 
					            connect(unwrap_or_else_out, v);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        unwrap_or_else_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn xor(expr: Expr<Self>, opt_b: Expr<Self>) -> Expr<Self> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let xor_out = wire(Expr::ty(expr));
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(_) = expr {
 | 
				
			||||||
 | 
					            #[hdl]
 | 
				
			||||||
 | 
					            if let HdlNone = opt_b {
 | 
				
			||||||
 | 
					                connect(xor_out, expr);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                connect(xor_out, Expr::ty(expr).HdlNone());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            connect(xor_out, opt_b);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        xor_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn zip<U: Type>(expr: Expr<Self>, other: Expr<HdlOption<U>>) -> Expr<HdlOption<(T, U)>> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let zip_out = wire(HdlOption[(Expr::ty(expr).HdlSome, Expr::ty(other).HdlSome)]);
 | 
				
			||||||
 | 
					        connect(zip_out, Expr::ty(zip_out).HdlNone());
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(l) = expr {
 | 
				
			||||||
 | 
					            #[hdl]
 | 
				
			||||||
 | 
					            if let HdlSome(r) = other {
 | 
				
			||||||
 | 
					                connect(zip_out, HdlSome((l, r)));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        zip_out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Type> HdlOption<HdlOption<T>> {
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn flatten(expr: Expr<Self>) -> Expr<HdlOption<T>> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let flattened = wire(Expr::ty(expr).HdlSome);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        match expr {
 | 
				
			||||||
 | 
					            HdlSome(v) => connect(flattened, v),
 | 
				
			||||||
 | 
					            HdlNone => connect(flattened, Expr::ty(expr).HdlSome.HdlNone()),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        flattened
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Type, U: Type> HdlOption<(T, U)> {
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn unzip(expr: Expr<Self>) -> Expr<(HdlOption<T>, HdlOption<U>)> {
 | 
				
			||||||
 | 
					        let (t, u) = Expr::ty(expr).HdlSome;
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let unzipped = wire((HdlOption[t], HdlOption[u]));
 | 
				
			||||||
 | 
					        connect(unzipped, (HdlOption[t].HdlNone(), HdlOption[u].HdlNone()));
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        if let HdlSome(v) = expr {
 | 
				
			||||||
 | 
					            connect(unzipped.0, HdlSome(v.0));
 | 
				
			||||||
 | 
					            connect(unzipped.1, HdlSome(v.1));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        unzipped
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ use crate::{
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{CanonicalType, Type},
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
    util::ScopedRef,
 | 
					    util::ScopedRef,
 | 
				
			||||||
    wire::Wire,
 | 
					    wire::{IncompleteWire, Wire},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use hashbrown::{hash_map::Entry, HashMap, HashSet};
 | 
					use hashbrown::{hash_map::Entry, HashMap, HashSet};
 | 
				
			||||||
use num_bigint::BigInt;
 | 
					use num_bigint::BigInt;
 | 
				
			||||||
| 
						 | 
					@ -118,9 +118,35 @@ pub trait BlockRef: 'static + Send + Sync + Copy + Eq + Hash + fmt::Debug {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl BlockRef for BlockId {}
 | 
					impl BlockRef for BlockId {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) enum IncompleteDeclaration {
 | 
				
			||||||
 | 
					    Incomplete {
 | 
				
			||||||
 | 
					        name: ScopedNameId,
 | 
				
			||||||
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    Complete(StmtDeclaration<ModuleBuilding>),
 | 
				
			||||||
 | 
					    Taken,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Debug for IncompleteDeclaration {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Incomplete {
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                source_location: _,
 | 
				
			||||||
 | 
					            } => f
 | 
				
			||||||
 | 
					                .debug_struct("Incomplete")
 | 
				
			||||||
 | 
					                .field("name", name)
 | 
				
			||||||
 | 
					                .finish_non_exhaustive(),
 | 
				
			||||||
 | 
					            Self::Complete(v) => v.fmt(f),
 | 
				
			||||||
 | 
					            Self::Taken => f.write_str("Taken"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct BuilderBlock {
 | 
					pub struct BuilderBlock {
 | 
				
			||||||
    memories: Vec<Rc<RefCell<MemBuilderTarget>>>,
 | 
					    memories: Vec<Rc<RefCell<MemBuilderTarget>>>,
 | 
				
			||||||
 | 
					    incomplete_declarations: Vec<Rc<RefCell<IncompleteDeclaration>>>,
 | 
				
			||||||
    stmts: Vec<Stmt<ModuleBuilding>>,
 | 
					    stmts: Vec<Stmt<ModuleBuilding>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -831,13 +857,34 @@ impl From<NormalModuleBody<ModuleBuilding>> for NormalModuleBody {
 | 
				
			||||||
            annotations_map: &mut HashMap<StmtDeclaration<ModuleBuilding>, Vec<TargetedAnnotation>>,
 | 
					            annotations_map: &mut HashMap<StmtDeclaration<ModuleBuilding>, Vec<TargetedAnnotation>>,
 | 
				
			||||||
            block_id: BlockId,
 | 
					            block_id: BlockId,
 | 
				
			||||||
        ) -> Block {
 | 
					        ) -> Block {
 | 
				
			||||||
            let BuilderBlock { memories, stmts } = &mut blocks[block_id.as_usize()];
 | 
					            let BuilderBlock {
 | 
				
			||||||
 | 
					                memories,
 | 
				
			||||||
 | 
					                incomplete_declarations,
 | 
				
			||||||
 | 
					                stmts,
 | 
				
			||||||
 | 
					            } = &mut blocks[block_id.as_usize()];
 | 
				
			||||||
            let memories = Interned::from_iter(
 | 
					            let memories = Interned::from_iter(
 | 
				
			||||||
                memories
 | 
					                memories
 | 
				
			||||||
                    .drain(..)
 | 
					                    .drain(..)
 | 
				
			||||||
                    .filter_map(|memory| memory.borrow().make_memory()),
 | 
					                    .filter_map(|memory| memory.borrow().make_memory()),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            let stmts = std::mem::take(stmts);
 | 
					            let stmts = Vec::from_iter(
 | 
				
			||||||
 | 
					                incomplete_declarations
 | 
				
			||||||
 | 
					                    .drain(..)
 | 
				
			||||||
 | 
					                    .map(|decl| {
 | 
				
			||||||
 | 
					                        match std::mem::replace(
 | 
				
			||||||
 | 
					                            &mut *decl.borrow_mut(),
 | 
				
			||||||
 | 
					                            IncompleteDeclaration::Taken,
 | 
				
			||||||
 | 
					                        ) {
 | 
				
			||||||
 | 
					                            IncompleteDeclaration::Incomplete {
 | 
				
			||||||
 | 
					                                name,
 | 
				
			||||||
 | 
					                                source_location,
 | 
				
			||||||
 | 
					                            } => panic!("incomplete declaration: {name:?}\nat: {source_location}"),
 | 
				
			||||||
 | 
					                            IncompleteDeclaration::Complete(v) => Stmt::Declaration(v),
 | 
				
			||||||
 | 
					                            IncompleteDeclaration::Taken => unreachable!(),
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .chain(stmts.drain(..)),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
            let stmts = Interned::from_iter(stmts.into_iter().map(|stmt| {
 | 
					            let stmts = Interned::from_iter(stmts.into_iter().map(|stmt| {
 | 
				
			||||||
                match stmt {
 | 
					                match stmt {
 | 
				
			||||||
                    Stmt::Connect(stmt) => stmt.into(),
 | 
					                    Stmt::Connect(stmt) => stmt.into(),
 | 
				
			||||||
| 
						 | 
					@ -908,6 +955,7 @@ impl NormalModuleBody<ModuleBuilding> {
 | 
				
			||||||
        let index = self.body.blocks.len();
 | 
					        let index = self.body.blocks.len();
 | 
				
			||||||
        self.body.blocks.push(BuilderBlock {
 | 
					        self.body.blocks.push(BuilderBlock {
 | 
				
			||||||
            memories: vec![],
 | 
					            memories: vec![],
 | 
				
			||||||
 | 
					            incomplete_declarations: vec![],
 | 
				
			||||||
            stmts: vec![],
 | 
					            stmts: vec![],
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        BlockId(index)
 | 
					        BlockId(index)
 | 
				
			||||||
| 
						 | 
					@ -1943,6 +1991,7 @@ impl ModuleBuilder {
 | 
				
			||||||
                body: BuilderModuleBody {
 | 
					                body: BuilderModuleBody {
 | 
				
			||||||
                    blocks: vec![BuilderBlock {
 | 
					                    blocks: vec![BuilderBlock {
 | 
				
			||||||
                        memories: vec![],
 | 
					                        memories: vec![],
 | 
				
			||||||
 | 
					                        incomplete_declarations: vec![],
 | 
				
			||||||
                        stmts: vec![],
 | 
					                        stmts: vec![],
 | 
				
			||||||
                    }],
 | 
					                    }],
 | 
				
			||||||
                    annotations_map: HashMap::new(),
 | 
					                    annotations_map: HashMap::new(),
 | 
				
			||||||
| 
						 | 
					@ -2156,6 +2205,42 @@ pub fn wire<T: Type>(implicit_name: ImplicitName<'_>, ty: T) -> Expr<T> {
 | 
				
			||||||
    wire_with_loc(implicit_name.0, SourceLocation::caller(), ty)
 | 
					    wire_with_loc(implicit_name.0, SourceLocation::caller(), ty)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[track_caller]
 | 
				
			||||||
 | 
					fn incomplete_declaration(
 | 
				
			||||||
 | 
					    name: &str,
 | 
				
			||||||
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
 | 
					) -> Rc<RefCell<IncompleteDeclaration>> {
 | 
				
			||||||
 | 
					    ModuleBuilder::with(|m| {
 | 
				
			||||||
 | 
					        let mut impl_ = m.impl_.borrow_mut();
 | 
				
			||||||
 | 
					        let scoped_name = ScopedNameId(m.name, impl_.name_id_gen.gen(name.intern()));
 | 
				
			||||||
 | 
					        drop(impl_);
 | 
				
			||||||
 | 
					        let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete {
 | 
				
			||||||
 | 
					            name: scoped_name,
 | 
				
			||||||
 | 
					            source_location,
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        let mut impl_ = m.impl_.borrow_mut();
 | 
				
			||||||
 | 
					        impl_
 | 
				
			||||||
 | 
					            .body
 | 
				
			||||||
 | 
					            .builder_normal_body()
 | 
				
			||||||
 | 
					            .block(m.block_stack.top())
 | 
				
			||||||
 | 
					            .incomplete_declarations
 | 
				
			||||||
 | 
					            .push(retval.clone());
 | 
				
			||||||
 | 
					        retval
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[track_caller]
 | 
				
			||||||
 | 
					pub fn incomplete_wire_with_loc(name: &str, source_location: SourceLocation) -> IncompleteWire {
 | 
				
			||||||
 | 
					    IncompleteWire {
 | 
				
			||||||
 | 
					        declaration: incomplete_declaration(name, source_location),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[track_caller]
 | 
				
			||||||
 | 
					pub fn incomplete_wire(implicit_name: ImplicitName<'_>) -> IncompleteWire {
 | 
				
			||||||
 | 
					    incomplete_wire_with_loc(implicit_name.0, SourceLocation::caller())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[track_caller]
 | 
					#[track_caller]
 | 
				
			||||||
pub fn reg_builder_with_loc(name: &str, source_location: SourceLocation) -> RegBuilder<(), (), ()> {
 | 
					pub fn reg_builder_with_loc(name: &str, source_location: SourceLocation) -> RegBuilder<(), (), ()> {
 | 
				
			||||||
    ModuleBuilder::with(|m| {
 | 
					    ModuleBuilder::with(|m| {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,8 @@ pub use crate::{
 | 
				
			||||||
    int::{Bool, DynSize, IntCmp, KnownSize, SInt, SIntType, Size, UInt, UIntType},
 | 
					    int::{Bool, DynSize, IntCmp, KnownSize, SInt, SIntType, Size, UInt, UIntType},
 | 
				
			||||||
    memory::{Mem, MemBuilder, ReadUnderWrite},
 | 
					    memory::{Mem, MemBuilder, ReadUnderWrite},
 | 
				
			||||||
    module::{
 | 
					    module::{
 | 
				
			||||||
        annotate, connect, connect_any, instance, memory, memory_array, memory_with_init,
 | 
					        annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array,
 | 
				
			||||||
        reg_builder, wire, Instance, Module, ModuleBuilder,
 | 
					        memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    reg::Reg,
 | 
					    reg::Reg,
 | 
				
			||||||
    reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
 | 
					    reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,3 +25,5 @@ pub use scoped_ref::ScopedRef;
 | 
				
			||||||
pub use misc::{
 | 
					pub use misc::{
 | 
				
			||||||
    interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice,
 | 
					    interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod ready_valid;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								crates/fayalite/src/util/ready_valid.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								crates/fayalite/src/util/ready_valid.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					use crate::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[hdl]
 | 
				
			||||||
 | 
					pub struct ReadyValid<T> {
 | 
				
			||||||
 | 
					    pub data: HdlOption<T>,
 | 
				
			||||||
 | 
					    #[hdl(flip)]
 | 
				
			||||||
 | 
					    pub ready: Bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Type> ReadyValid<T> {
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    pub fn fire(expr: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let fire: Bool = wire();
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        match expr.data {
 | 
				
			||||||
 | 
					            HdlNone => connect(fire, false),
 | 
				
			||||||
 | 
					            HdlSome(_) => connect(fire, expr.ready),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fire
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[hdl]
 | 
				
			||||||
 | 
					    pub fn map<R: Type>(
 | 
				
			||||||
 | 
					        expr: Expr<Self>,
 | 
				
			||||||
 | 
					        f: impl FnOnce(Expr<T>) -> Expr<R>,
 | 
				
			||||||
 | 
					    ) -> Expr<ReadyValid<R>> {
 | 
				
			||||||
 | 
					        let data = HdlOption::map(expr.data, f);
 | 
				
			||||||
 | 
					        #[hdl]
 | 
				
			||||||
 | 
					        let mapped = wire(ReadyValid[Expr::ty(data).HdlSome]);
 | 
				
			||||||
 | 
					        connect(mapped.data, data);
 | 
				
			||||||
 | 
					        connect(expr.ready, mapped.ready);
 | 
				
			||||||
 | 
					        mapped
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    expr::Flow,
 | 
					    expr::{Expr, Flow, ToExpr},
 | 
				
			||||||
    intern::Interned,
 | 
					    intern::Interned,
 | 
				
			||||||
    module::{NameId, ScopedNameId},
 | 
					    module::{IncompleteDeclaration, NameId, ScopedNameId, StmtDeclaration, StmtWire},
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{CanonicalType, Type},
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use std::fmt;
 | 
					use std::{cell::RefCell, fmt, rc::Rc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Hash)]
 | 
				
			||||||
pub struct Wire<T: Type> {
 | 
					pub struct Wire<T: Type> {
 | 
				
			||||||
| 
						 | 
					@ -76,3 +76,57 @@ impl<T: Type> Wire<T> {
 | 
				
			||||||
        true
 | 
					        true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone)]
 | 
				
			||||||
 | 
					pub struct IncompleteWire {
 | 
				
			||||||
 | 
					    pub(crate) declaration: Rc<RefCell<IncompleteDeclaration>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IncompleteWire {
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn complete<T: Type>(&mut self, ty: T) -> Expr<T> {
 | 
				
			||||||
 | 
					        let canonical_type = ty.canonical();
 | 
				
			||||||
 | 
					        let mut declaration = self.declaration.borrow_mut();
 | 
				
			||||||
 | 
					        if let IncompleteDeclaration::Incomplete {
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            source_location,
 | 
				
			||||||
 | 
					        } = *declaration
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            *declaration = IncompleteDeclaration::Complete(
 | 
				
			||||||
 | 
					                StmtWire {
 | 
				
			||||||
 | 
					                    annotations: (),
 | 
				
			||||||
 | 
					                    wire: Wire {
 | 
				
			||||||
 | 
					                        name,
 | 
				
			||||||
 | 
					                        source_location,
 | 
				
			||||||
 | 
					                        ty: canonical_type,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                .into(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        match *declaration {
 | 
				
			||||||
 | 
					            IncompleteDeclaration::Complete(StmtDeclaration::Wire(StmtWire {
 | 
				
			||||||
 | 
					                wire:
 | 
				
			||||||
 | 
					                    Wire {
 | 
				
			||||||
 | 
					                        name,
 | 
				
			||||||
 | 
					                        source_location,
 | 
				
			||||||
 | 
					                        ty: wire_ty,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ..
 | 
				
			||||||
 | 
					            })) => {
 | 
				
			||||||
 | 
					                drop(declaration);
 | 
				
			||||||
 | 
					                assert_eq!(wire_ty, canonical_type, "type mismatch");
 | 
				
			||||||
 | 
					                Wire {
 | 
				
			||||||
 | 
					                    name,
 | 
				
			||||||
 | 
					                    source_location,
 | 
				
			||||||
 | 
					                    ty,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                .to_expr()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            IncompleteDeclaration::Taken => panic!("can't use wire outside of containing module"),
 | 
				
			||||||
 | 
					            IncompleteDeclaration::Complete(_) | IncompleteDeclaration::Incomplete { .. } => {
 | 
				
			||||||
 | 
					                unreachable!()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					 --> tests/ui/hdl_types.rs:5:1
 | 
				
			||||||
  |
 | 
					  |
 | 
				
			||||||
5 | #[hdl]
 | 
					5 | #[hdl]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue