forked from libre-chip/fayalite
		
	add support for #[hdl(sim)] enum_ty.Variant(value) and #[hdl(sim)] EnumTy::Variant(value) and non-sim variants too
This commit is contained in:
		
							parent
							
								
									9092e45447
								
							
						
					
					
						commit
						c4b6a0fee6
					
				
					 9 changed files with 817 additions and 370 deletions
				
			
		| 
						 | 
				
			
			@ -220,6 +220,7 @@ forward_fold!(syn::ExprArray => fold_expr_array);
 | 
			
		|||
forward_fold!(syn::ExprCall => fold_expr_call);
 | 
			
		||||
forward_fold!(syn::ExprIf => fold_expr_if);
 | 
			
		||||
forward_fold!(syn::ExprMatch => fold_expr_match);
 | 
			
		||||
forward_fold!(syn::ExprMethodCall => fold_expr_method_call);
 | 
			
		||||
forward_fold!(syn::ExprPath => fold_expr_path);
 | 
			
		||||
forward_fold!(syn::ExprRepeat => fold_expr_repeat);
 | 
			
		||||
forward_fold!(syn::ExprStruct => fold_expr_struct);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -130,6 +130,8 @@ pub(crate) struct ParsedEnum {
 | 
			
		|||
    pub(crate) variants: Punctuated<ParsedVariant, Token![,]>,
 | 
			
		||||
    pub(crate) match_variant_ident: Ident,
 | 
			
		||||
    pub(crate) sim_value_ident: Ident,
 | 
			
		||||
    pub(crate) sim_builder_ident: Ident,
 | 
			
		||||
    pub(crate) sim_builder_ty_field_ident: Ident,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ParsedEnum {
 | 
			
		||||
| 
						 | 
				
			
			@ -192,6 +194,8 @@ impl ParsedEnum {
 | 
			
		|||
            variants,
 | 
			
		||||
            match_variant_ident: format_ident!("__{}__MatchVariant", ident),
 | 
			
		||||
            sim_value_ident: format_ident!("__{}__SimValue", ident),
 | 
			
		||||
            sim_builder_ident: format_ident!("__{}__SimBuilder", ident),
 | 
			
		||||
            sim_builder_ty_field_ident: format_ident!("__ty", span = ident.span()),
 | 
			
		||||
            ident,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -210,6 +214,8 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
            variants,
 | 
			
		||||
            match_variant_ident,
 | 
			
		||||
            sim_value_ident,
 | 
			
		||||
            sim_builder_ident,
 | 
			
		||||
            sim_builder_ty_field_ident,
 | 
			
		||||
        } = self;
 | 
			
		||||
        let span = ident.span();
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
| 
						 | 
				
			
			@ -412,6 +418,33 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
            )),
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let mut struct_attrs = attrs.clone();
 | 
			
		||||
        struct_attrs.push(parse_quote_spanned! {span=>
 | 
			
		||||
            #[allow(dead_code, non_camel_case_types)]
 | 
			
		||||
        });
 | 
			
		||||
        ItemStruct {
 | 
			
		||||
            attrs: struct_attrs,
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: Token,
 | 
			
		||||
            ident: sim_builder_ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: FieldsNamed {
 | 
			
		||||
                brace_token: *brace_token,
 | 
			
		||||
                named: Punctuated::from_iter([Field {
 | 
			
		||||
                    attrs: vec![],
 | 
			
		||||
                    vis: Visibility::Inherited,
 | 
			
		||||
                    mutability: FieldMutability::None,
 | 
			
		||||
                    ident: Some(sim_builder_ty_field_ident.clone()),
 | 
			
		||||
                    colon_token: Some(Token),
 | 
			
		||||
                    ty: parse_quote_spanned! {span=>
 | 
			
		||||
                        #target #type_generics
 | 
			
		||||
                    },
 | 
			
		||||
                }]),
 | 
			
		||||
            }
 | 
			
		||||
            .into(),
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let mut enum_attrs = attrs.clone();
 | 
			
		||||
        enum_attrs.push(parse_quote_spanned! {span=>
 | 
			
		||||
            #[::fayalite::__std::prelude::v1::derive(
 | 
			
		||||
| 
						 | 
				
			
			@ -538,6 +571,25 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    #[automatically_derived]
 | 
			
		||||
                    impl #impl_generics #sim_builder_ident #type_generics
 | 
			
		||||
                    #where_clause
 | 
			
		||||
                    {
 | 
			
		||||
                        #[allow(non_snake_case, dead_code)]
 | 
			
		||||
                        #vis fn #ident<__V: ::fayalite::sim::value::ToSimValueWithType<#ty>>(
 | 
			
		||||
                            #self_token,
 | 
			
		||||
                            v: __V,
 | 
			
		||||
                        ) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
 | 
			
		||||
                            let v = ::fayalite::sim::value::ToSimValueWithType::into_sim_value_with_type(
 | 
			
		||||
                                v,
 | 
			
		||||
                                #self_token.#sim_builder_ty_field_ident.#ident,
 | 
			
		||||
                            );
 | 
			
		||||
                            ::fayalite::sim::value::SimValue::from_value(
 | 
			
		||||
                                #self_token.#sim_builder_ty_field_ident,
 | 
			
		||||
                                #sim_value_ident::#ident(v, ::fayalite::enum_::EnumPaddingSimValue::new()),
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                quote_spanned! {span=>
 | 
			
		||||
| 
						 | 
				
			
			@ -556,6 +608,18 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    #[automatically_derived]
 | 
			
		||||
                    impl #impl_generics #sim_builder_ident #type_generics
 | 
			
		||||
                    #where_clause
 | 
			
		||||
                    {
 | 
			
		||||
                        #[allow(non_snake_case, dead_code)]
 | 
			
		||||
                        #vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
 | 
			
		||||
                            ::fayalite::sim::value::SimValue::from_value(
 | 
			
		||||
                                #self_token.#sim_builder_ty_field_ident,
 | 
			
		||||
                                #sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .to_tokens(tokens);
 | 
			
		||||
| 
						 | 
				
			
			@ -848,6 +912,7 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
            impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type SimBuilder = #sim_builder_ident #type_generics;
 | 
			
		||||
                fn match_activate_scope(
 | 
			
		||||
                    v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
			
		||||
                ) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
 | 
			
		||||
| 
						 | 
				
			
			@ -884,6 +949,15 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
                    ::fayalite::sim::value::SimValue::from_value(ty, self)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::__std::convert::From<#target #type_generics>
 | 
			
		||||
            for #sim_builder_ident #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                fn from(#sim_builder_ty_field_ident: #target #type_generics) -> Self {
 | 
			
		||||
                    Self { #sim_builder_ty_field_ident }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1687,6 +1687,8 @@ impl Fold for Visitor<'_> {
 | 
			
		|||
                Repeat => process_hdl_repeat,
 | 
			
		||||
                Struct => process_hdl_struct,
 | 
			
		||||
                Tuple => process_hdl_tuple,
 | 
			
		||||
                MethodCall => process_hdl_method_call,
 | 
			
		||||
                Call => process_hdl_call,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,20 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    kw,
 | 
			
		||||
    module::transform_body::{ExprOptions, Visitor},
 | 
			
		||||
    module::transform_body::{
 | 
			
		||||
        expand_match::{parse_enum_path, EnumPath},
 | 
			
		||||
        ExprOptions, Visitor,
 | 
			
		||||
    },
 | 
			
		||||
    HdlAttr,
 | 
			
		||||
};
 | 
			
		||||
use quote::{format_ident, quote_spanned};
 | 
			
		||||
use std::mem;
 | 
			
		||||
use syn::{
 | 
			
		||||
    parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, ExprRepeat, ExprStruct,
 | 
			
		||||
    ExprTuple, FieldValue, TypePath,
 | 
			
		||||
    parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, token::Paren, Expr, ExprArray,
 | 
			
		||||
    ExprCall, ExprGroup, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprStruct, ExprTuple,
 | 
			
		||||
    FieldValue, Token, TypePath,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
impl Visitor<'_> {
 | 
			
		||||
| 
						 | 
				
			
			@ -162,4 +168,107 @@ impl Visitor<'_> {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn process_hdl_call(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
 | 
			
		||||
        mut expr_call: ExprCall,
 | 
			
		||||
    ) -> Expr {
 | 
			
		||||
        let span = hdl_attr.kw.span;
 | 
			
		||||
        let mut func = &mut *expr_call.func;
 | 
			
		||||
        let EnumPath {
 | 
			
		||||
            variant_path: _,
 | 
			
		||||
            enum_path,
 | 
			
		||||
            variant_name,
 | 
			
		||||
        } = loop {
 | 
			
		||||
            match func {
 | 
			
		||||
                Expr::Group(ExprGroup { expr, .. }) | Expr::Paren(ExprParen { expr, .. }) => {
 | 
			
		||||
                    func = &mut **expr;
 | 
			
		||||
                }
 | 
			
		||||
                Expr::Path(_) => {
 | 
			
		||||
                    let Expr::Path(ExprPath { attrs, qself, path }) =
 | 
			
		||||
                        mem::replace(func, Expr::PLACEHOLDER)
 | 
			
		||||
                    else {
 | 
			
		||||
                        unreachable!();
 | 
			
		||||
                    };
 | 
			
		||||
                    match parse_enum_path(TypePath { qself, path }) {
 | 
			
		||||
                        Ok(path) => break path,
 | 
			
		||||
                        Err(path) => {
 | 
			
		||||
                            self.errors.error(&path, "unsupported enum variant path");
 | 
			
		||||
                            let TypePath { qself, path } = path;
 | 
			
		||||
                            *func = ExprPath { attrs, qself, path }.into();
 | 
			
		||||
                            return expr_call.into();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                _ => {
 | 
			
		||||
                    self.errors.error(
 | 
			
		||||
                        &expr_call.func,
 | 
			
		||||
                        "#[hdl] function call -- function must be a possibly-parenthesized path",
 | 
			
		||||
                    );
 | 
			
		||||
                    return expr_call.into();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        self.process_hdl_method_call(
 | 
			
		||||
            hdl_attr,
 | 
			
		||||
            ExprMethodCall {
 | 
			
		||||
                attrs: expr_call.attrs,
 | 
			
		||||
                receiver: parse_quote_spanned! {span=>
 | 
			
		||||
                    <#enum_path as ::fayalite::ty::StaticType>::TYPE
 | 
			
		||||
                },
 | 
			
		||||
                dot_token: Token,
 | 
			
		||||
                method: variant_name,
 | 
			
		||||
                turbofish: None,
 | 
			
		||||
                paren_token: expr_call.paren_token,
 | 
			
		||||
                args: expr_call.args,
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn process_hdl_method_call(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        hdl_attr: HdlAttr<ExprOptions, kw::hdl>,
 | 
			
		||||
        mut expr_method_call: ExprMethodCall,
 | 
			
		||||
    ) -> Expr {
 | 
			
		||||
        let ExprOptions { sim } = hdl_attr.body;
 | 
			
		||||
        let span = hdl_attr.kw.span;
 | 
			
		||||
        // remove any number of groups and up to one paren
 | 
			
		||||
        let mut receiver = &mut *expr_method_call.receiver;
 | 
			
		||||
        let mut has_group = false;
 | 
			
		||||
        let receiver = loop {
 | 
			
		||||
            match receiver {
 | 
			
		||||
                Expr::Group(ExprGroup { expr, .. }) => {
 | 
			
		||||
                    has_group = true;
 | 
			
		||||
                    receiver = expr;
 | 
			
		||||
                }
 | 
			
		||||
                Expr::Paren(ExprParen { expr, .. }) => break &mut **expr,
 | 
			
		||||
                receiver @ Expr::Path(_) => break receiver,
 | 
			
		||||
                _ => {
 | 
			
		||||
                    if !has_group {
 | 
			
		||||
                        self.errors.error(
 | 
			
		||||
                            &expr_method_call.receiver,
 | 
			
		||||
                            "#[hdl] on a method call needs parenthesized receiver",
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                    break &mut *expr_method_call.receiver;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let func = if sim.is_some() {
 | 
			
		||||
            parse_quote_spanned! {span=>
 | 
			
		||||
                ::fayalite::enum_::enum_type_to_sim_builder
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            parse_quote_spanned! {span=>
 | 
			
		||||
                ::fayalite::enum_::assert_is_enum_type
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        *expr_method_call.receiver = ExprCall {
 | 
			
		||||
            attrs: vec![],
 | 
			
		||||
            func,
 | 
			
		||||
            paren_token: Paren(span),
 | 
			
		||||
            args: Punctuated::from_iter([mem::replace(receiver, Expr::PLACEHOLDER)]),
 | 
			
		||||
        }
 | 
			
		||||
        .into();
 | 
			
		||||
        expr_method_call.into()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -380,13 +380,13 @@ impl ToTokens for MatchPatSimple {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct EnumPath {
 | 
			
		||||
    variant_path: Path,
 | 
			
		||||
    enum_path: Path,
 | 
			
		||||
    variant_name: Ident,
 | 
			
		||||
pub(crate) struct EnumPath {
 | 
			
		||||
    pub(crate) variant_path: Path,
 | 
			
		||||
    pub(crate) enum_path: Path,
 | 
			
		||||
    pub(crate) variant_name: Ident,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> {
 | 
			
		||||
pub(crate) fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> {
 | 
			
		||||
    let TypePath {
 | 
			
		||||
        qself: None,
 | 
			
		||||
        path: variant_path,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue