forked from libre-chip/fayalite
support Rust's default binding modes when destructuring with #[hdl(sim)] let/match
This commit is contained in:
parent
053c1b2b10
commit
2817cd3d58
6 changed files with 371 additions and 70 deletions
|
|
@ -88,6 +88,9 @@ impl Visitor<'_> {
|
|||
field.expr = parse_quote_spanned! {field.member.span()=>
|
||||
::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr))
|
||||
};
|
||||
field
|
||||
.colon_token
|
||||
.get_or_insert(Token));
|
||||
}
|
||||
return parse_quote_spanned! {name_span=>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt, format_ident, quote_spanned};
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::BTreeMap;
|
||||
use syn::{
|
||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr,
|
||||
PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment,
|
||||
|
|
@ -24,65 +24,65 @@ use syn::{
|
|||
|
||||
macro_rules! visit_trait {
|
||||
(
|
||||
$($vis:vis fn $fn:ident($state:ident: _, $value:ident: &$Value:ty) $block:block)*
|
||||
$($vis:vis fn $fn:ident($state:ident: _, $value:ident: &mut $Value:ty) $block:block)*
|
||||
) => {
|
||||
trait VisitMatchPat<'a> {
|
||||
$(fn $fn(&mut self, $value: &'a $Value) {
|
||||
$(fn $fn(&mut self, $value: &'a mut $Value) {
|
||||
$fn(self, $value);
|
||||
})*
|
||||
}
|
||||
|
||||
$($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a $Value) $block)*
|
||||
$($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a mut $Value) $block)*
|
||||
};
|
||||
}
|
||||
|
||||
visit_trait! {
|
||||
fn visit_match_pat_binding(_state: _, v: &MatchPatBinding) {
|
||||
let MatchPatBinding { ident: _ } = v;
|
||||
fn visit_match_pat_binding(_state: _, v: &mut MatchPatBinding) {
|
||||
let MatchPatBinding { mutability: _, ident: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_wild(_state: _, v: &MatchPatWild) {
|
||||
fn visit_match_pat_wild(_state: _, v: &mut MatchPatWild) {
|
||||
let MatchPatWild { underscore_token: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_rest(_state: _, v: &MatchPatRest) {
|
||||
fn visit_match_pat_rest(_state: _, v: &mut MatchPatRest) {
|
||||
let MatchPatRest { dot2_token: _ } = v;
|
||||
}
|
||||
fn visit_match_pat_paren(state: _, v: &MatchPatParen<MatchPat>) {
|
||||
fn visit_match_pat_paren(state: _, v: &mut MatchPatParen<MatchPat>) {
|
||||
let MatchPatParen { paren_token: _, pat } = v;
|
||||
state.visit_match_pat(pat);
|
||||
}
|
||||
fn visit_match_pat_paren_simple(state: _, v: &MatchPatParen<MatchPatSimple>) {
|
||||
fn visit_match_pat_paren_simple(state: _, v: &mut MatchPatParen<MatchPatSimple>) {
|
||||
let MatchPatParen { paren_token: _, pat } = v;
|
||||
state.visit_match_pat_simple(pat);
|
||||
}
|
||||
fn visit_match_pat_or(state: _, v: &MatchPatOr<MatchPat>) {
|
||||
fn visit_match_pat_or(state: _, v: &mut MatchPatOr<MatchPat>) {
|
||||
let MatchPatOr { leading_vert: _, cases } = v;
|
||||
for v in cases {
|
||||
state.visit_match_pat(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_or_simple(state: _, v: &MatchPatOr<MatchPatSimple>) {
|
||||
fn visit_match_pat_or_simple(state: _, v: &mut MatchPatOr<MatchPatSimple>) {
|
||||
let MatchPatOr { leading_vert: _, cases } = v;
|
||||
for v in cases {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_struct_field(state: _, v: &MatchPatStructField) {
|
||||
fn visit_match_pat_struct_field(state: _, v: &mut MatchPatStructField) {
|
||||
let MatchPatStructField { field_name: _, colon_token: _, pat } = v;
|
||||
state.visit_match_pat_simple(pat);
|
||||
}
|
||||
fn visit_match_pat_struct(state: _, v: &MatchPatStruct) {
|
||||
fn visit_match_pat_struct(state: _, v: &mut MatchPatStruct) {
|
||||
let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v;
|
||||
for v in fields {
|
||||
state.visit_match_pat_struct_field(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_tuple(state: _, v: &MatchPatTuple) {
|
||||
fn visit_match_pat_tuple(state: _, v: &mut MatchPatTuple) {
|
||||
let MatchPatTuple { paren_token: _, fields } = v;
|
||||
for v in fields {
|
||||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_enum_variant(state: _, v: &MatchPatEnumVariant) {
|
||||
fn visit_match_pat_enum_variant(state: _, v: &mut MatchPatEnumVariant) {
|
||||
let MatchPatEnumVariant {
|
||||
match_span:_,
|
||||
sim:_,
|
||||
|
|
@ -95,7 +95,7 @@ visit_trait! {
|
|||
state.visit_match_pat_simple(v);
|
||||
}
|
||||
}
|
||||
fn visit_match_pat_simple(state: _, v: &MatchPatSimple) {
|
||||
fn visit_match_pat_simple(state: _, v: &mut MatchPatSimple) {
|
||||
match v {
|
||||
MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v),
|
||||
MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v),
|
||||
|
|
@ -104,7 +104,7 @@ visit_trait! {
|
|||
MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v),
|
||||
}
|
||||
}
|
||||
fn visit_match_pat(state: _, v: &MatchPat) {
|
||||
fn visit_match_pat(state: _, v: &mut MatchPat) {
|
||||
match v {
|
||||
MatchPat::Simple(v) => state.visit_match_pat_simple(v),
|
||||
MatchPat::Or(v) => state.visit_match_pat_or(v),
|
||||
|
|
@ -118,13 +118,15 @@ visit_trait! {
|
|||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatBinding<> {
|
||||
mutability: Option<Token![mut]>,
|
||||
ident: Ident,
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPatBinding {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self { ident } = self;
|
||||
let Self { mutability, ident } = self;
|
||||
mutability.to_tokens(tokens);
|
||||
ident.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
|
@ -211,12 +213,20 @@ impl ToTokens for MatchPatStructField {
|
|||
colon_token,
|
||||
pat,
|
||||
} = self;
|
||||
field_name.to_tokens(tokens);
|
||||
if let (None, MatchPatSimple::Binding(MatchPatBinding { ident })) = (colon_token, pat) {
|
||||
if let (
|
||||
None,
|
||||
MatchPatSimple::Binding(MatchPatBinding {
|
||||
mutability: _,
|
||||
ident,
|
||||
}),
|
||||
) = (colon_token, pat)
|
||||
{
|
||||
if field_name == ident {
|
||||
pat.to_tokens(tokens);
|
||||
return;
|
||||
}
|
||||
}
|
||||
field_name.to_tokens(tokens);
|
||||
colon_token
|
||||
.unwrap_or_else(|| Token))
|
||||
.to_tokens(tokens);
|
||||
|
|
@ -450,7 +460,7 @@ trait ParseMatchPat: Sized {
|
|||
Pat::Ident(PatIdent {
|
||||
attrs: _,
|
||||
by_ref,
|
||||
mutability,
|
||||
mut mutability,
|
||||
ident,
|
||||
subpat,
|
||||
}) => {
|
||||
|
|
@ -459,10 +469,13 @@ trait ParseMatchPat: Sized {
|
|||
.errors
|
||||
.error(by_ref, "ref not allowed in #[hdl] patterns");
|
||||
}
|
||||
if let Some(mutability) = mutability {
|
||||
state
|
||||
.errors
|
||||
.error(mutability, "mut not allowed in #[hdl] patterns");
|
||||
if let Some(mut_token) = mutability {
|
||||
if state.sim.is_none() {
|
||||
state
|
||||
.errors
|
||||
.error(mut_token, "mut not allowed in #[hdl] patterns");
|
||||
mutability = None; // avoid duplicate errors
|
||||
}
|
||||
}
|
||||
if let Some((at_token, _)) = subpat {
|
||||
state
|
||||
|
|
@ -474,18 +487,26 @@ trait ParseMatchPat: Sized {
|
|||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
}) => Self::enum_variant(
|
||||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
),
|
||||
}) => {
|
||||
if let Some(mut_token) = mutability {
|
||||
state
|
||||
.errors
|
||||
.error(mut_token, "mut not allowed on unit variants");
|
||||
}
|
||||
Self::enum_variant(
|
||||
state,
|
||||
MatchPatEnumVariant {
|
||||
match_span: state.match_span,
|
||||
sim: state.sim,
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
Err(ident) => Ok(Self::simple(MatchPatSimple::Binding(MatchPatBinding {
|
||||
mutability,
|
||||
ident,
|
||||
}))),
|
||||
}
|
||||
|
|
@ -980,15 +1001,16 @@ struct HdlMatchParseState<'a> {
|
|||
|
||||
struct HdlLetPatVisitState<'a> {
|
||||
errors: &'a mut Errors,
|
||||
bindings: BTreeSet<&'a Ident>,
|
||||
bindings: BTreeMap<Ident, MatchPatBinding>,
|
||||
}
|
||||
|
||||
impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
||||
fn visit_match_pat_binding(&mut self, v: &'a MatchPatBinding) {
|
||||
self.bindings.insert(&v.ident);
|
||||
fn visit_match_pat_binding(&mut self, v: &'a mut MatchPatBinding) {
|
||||
self.bindings.insert(v.ident.clone(), v.clone());
|
||||
v.mutability = None;
|
||||
}
|
||||
|
||||
fn visit_match_pat_or(&mut self, v: &'a MatchPatOr<MatchPat>) {
|
||||
fn visit_match_pat_or(&mut self, v: &'a mut MatchPatOr<MatchPat>) {
|
||||
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||
self.errors.error(
|
||||
first_inner_vert,
|
||||
|
|
@ -998,7 +1020,7 @@ impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
|||
visit_match_pat_or(self, v);
|
||||
}
|
||||
|
||||
fn visit_match_pat_or_simple(&mut self, v: &'a MatchPatOr<MatchPatSimple>) {
|
||||
fn visit_match_pat_or_simple(&mut self, v: &'a mut MatchPatOr<MatchPatSimple>) {
|
||||
if let Some(first_inner_vert) = v.first_inner_vert() {
|
||||
self.errors.error(
|
||||
first_inner_vert,
|
||||
|
|
@ -1008,7 +1030,7 @@ impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> {
|
|||
visit_match_pat_or_simple(self, v);
|
||||
}
|
||||
|
||||
fn visit_match_pat_enum_variant(&mut self, v: &'a MatchPatEnumVariant) {
|
||||
fn visit_match_pat_enum_variant(&mut self, v: &'a mut MatchPatEnumVariant) {
|
||||
self.errors.error(v, "refutable pattern in let statement");
|
||||
}
|
||||
}
|
||||
|
|
@ -1048,7 +1070,7 @@ impl Visitor<'_> {
|
|||
.error(else_, "#[hdl] let ... else { ... } is not implemented");
|
||||
return empty_let();
|
||||
}
|
||||
let Ok(pat) = MatchPat::parse(
|
||||
let Ok(mut pat) = MatchPat::parse(
|
||||
&mut HdlMatchParseState {
|
||||
sim,
|
||||
match_span: span,
|
||||
|
|
@ -1060,20 +1082,27 @@ impl Visitor<'_> {
|
|||
};
|
||||
let mut state = HdlLetPatVisitState {
|
||||
errors: &mut self.errors,
|
||||
bindings: BTreeSet::new(),
|
||||
bindings: BTreeMap::new(),
|
||||
};
|
||||
state.visit_match_pat(&pat);
|
||||
state.visit_match_pat(&mut pat);
|
||||
let HdlLetPatVisitState {
|
||||
errors: _,
|
||||
bindings,
|
||||
} = state;
|
||||
let bindings_idents = bindings.keys();
|
||||
let bindings = bindings.values();
|
||||
let retval = if sim.is_some() {
|
||||
parse_quote_spanned! {span=>
|
||||
let (#(#bindings,)*) = {
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr));
|
||||
#let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token
|
||||
(#(#bindings,)*)
|
||||
let __match_value = #expr;
|
||||
let __match_value = {
|
||||
use ::fayalite::sim::value::match_sim_value::*;
|
||||
// use method syntax to deduce the correct trait to call
|
||||
::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value()
|
||||
};
|
||||
#let_token #pat #eq_token __match_value #semi_token
|
||||
(#(#bindings_idents,)*)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1105,7 +1134,7 @@ impl Visitor<'_> {
|
|||
__match_variant,
|
||||
);
|
||||
#let_token #pat #eq_token __match_variant #semi_token
|
||||
(#(#bindings,)* __scope,)
|
||||
(#(#bindings_idents,)* __scope,)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
@ -1142,8 +1171,13 @@ impl Visitor<'_> {
|
|||
quote_spanned! {span=>
|
||||
{
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
|
||||
let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr));
|
||||
#match_token ::fayalite::sim::value::SimValue::into_value(__match_expr) {
|
||||
let __match_value = #expr;
|
||||
let __match_value = {
|
||||
use ::fayalite::sim::value::match_sim_value::*;
|
||||
// use method syntax to deduce the correct trait to call
|
||||
::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value()
|
||||
};
|
||||
#match_token __match_value {
|
||||
#(#arms)*
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue