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