WIP: use HdlOption[the_type_var] or UInt[123 + n] for creating types
All checks were successful
/ test (push) Successful in 4m56s
All checks were successful
/ test (push) Successful in 4m56s
This commit is contained in:
parent
cd99dbc849
commit
5835b995a9
63 changed files with 13500 additions and 13210 deletions
|
@ -2,11 +2,14 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
fold::{impl_fold, DoFold},
|
||||
hdl_type_common::{
|
||||
known_items, ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser,
|
||||
},
|
||||
is_hdl_attr, kw,
|
||||
module::{check_name_conflicts_with_module_builder, ModuleIO, ModuleIOKind, ModuleKind},
|
||||
options, Errors, HdlAttr,
|
||||
};
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use num_bigint::BigInt;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use std::{borrow::Borrow, convert::Infallible};
|
||||
|
@ -87,9 +90,9 @@ macro_rules! with_debug_clone_and_fold {
|
|||
pub(crate) use with_debug_clone_and_fold;
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
pub(crate) struct HdlLetKindIO<Kind = ModuleIOKind> {
|
||||
pub(crate) struct HdlLetKindIO<Kind = ModuleIOKind, Ty = ParsedType> {
|
||||
pub(crate) colon_token: Token![:],
|
||||
pub(crate) ty: Box<Type>,
|
||||
pub(crate) ty: Box<Ty>,
|
||||
pub(crate) m: kw::m,
|
||||
pub(crate) dot_token: Token![.],
|
||||
pub(crate) kind: Kind,
|
||||
|
@ -98,6 +101,32 @@ with_debug_clone_and_fold! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Kind: Clone, T: ParseTypes<I>, I> ParseTypes<HdlLetKindIO<Kind, I>> for HdlLetKindIO<Kind, T> {
|
||||
fn parse_types(
|
||||
input: &mut HdlLetKindIO<Kind, I>,
|
||||
parser: &mut TypesParser<'_>,
|
||||
) -> Result<Self, ParseFailed> {
|
||||
let HdlLetKindIO {
|
||||
colon_token,
|
||||
ty,
|
||||
m,
|
||||
dot_token,
|
||||
kind,
|
||||
paren,
|
||||
ty_expr,
|
||||
} = input;
|
||||
Ok(Self {
|
||||
colon_token: *colon_token,
|
||||
ty: ParseTypes::parse_types(ty, parser)?,
|
||||
m: *m,
|
||||
dot_token: *dot_token,
|
||||
kind: kind.clone(),
|
||||
paren: *paren,
|
||||
ty_expr: ty_expr.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_single_fn_arg(input: ParseStream) -> syn::Result<Box<Expr>> {
|
||||
let retval = input.parse()?;
|
||||
let _: Option<Token![,]> = input.parse()?;
|
||||
|
@ -145,17 +174,19 @@ impl<Kind: ToTokens> HdlLetKindToTokens for HdlLetKindIO<Kind> {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct HdlLetKindInstance {
|
||||
pub(crate) m: kw::m,
|
||||
pub(crate) dot_token: Token![.],
|
||||
pub(crate) instance: kw::instance,
|
||||
pub(crate) paren: Paren,
|
||||
pub(crate) module: Box<Expr>,
|
||||
}
|
||||
|
||||
impl ParseTypes<Self> for HdlLetKindInstance {
|
||||
fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||
Ok(input.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
struct HdlLetKindInstance<> {
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
instance: kw::instance,
|
||||
paren: Paren,
|
||||
module: Box<Expr>,
|
||||
|
@ -167,14 +198,10 @@ impl HdlLetKindToTokens for HdlLetKindInstance {
|
|||
|
||||
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
m,
|
||||
dot_token,
|
||||
instance,
|
||||
paren,
|
||||
module,
|
||||
} = self;
|
||||
m.to_tokens(tokens);
|
||||
dot_token.to_tokens(tokens);
|
||||
instance.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| module.to_tokens(tokens));
|
||||
}
|
||||
|
@ -381,19 +408,21 @@ make_builder_method_enum! {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct HdlLetKindRegBuilder {
|
||||
pub(crate) ty: Option<(Token![:], Box<Type>)>,
|
||||
pub(crate) m: kw::m,
|
||||
pub(crate) dot_token: Token![.],
|
||||
pub(crate) reg_builder: kw::reg_builder,
|
||||
pub(crate) reg_builder_paren: Paren,
|
||||
pub(crate) clock_domain: Option<RegBuilderClockDomain>,
|
||||
pub(crate) reset: RegBuilderReset,
|
||||
}
|
||||
|
||||
impl ParseTypes<Self> for HdlLetKindRegBuilder {
|
||||
fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||
Ok(input.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
struct HdlLetKindRegBuilder<> {
|
||||
ty: Option<(Token![:], Box<Type>)>,
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
reg_builder: kw::reg_builder,
|
||||
reg_builder_paren: Paren,
|
||||
clock_domain: Option<RegBuilderClockDomain>,
|
||||
|
@ -406,10 +435,10 @@ impl HdlLetKindRegBuilder {
|
|||
input: ParseStream,
|
||||
parsed_ty: Option<(Token![:], Box<Type>)>,
|
||||
_after_ty: Token![=],
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
m_dot: Option<(kw::m, Token![.])>,
|
||||
reg_builder: kw::reg_builder,
|
||||
) -> syn::Result<Self> {
|
||||
check_empty_m_dot(m_dot, reg_builder)?;
|
||||
let _reg_builder_paren_inner;
|
||||
let reg_builder_paren = parenthesized!(_reg_builder_paren_inner in input);
|
||||
let mut clock_domain = None;
|
||||
|
@ -430,8 +459,6 @@ impl HdlLetKindRegBuilder {
|
|||
}
|
||||
Ok(Self {
|
||||
ty: parsed_ty,
|
||||
m,
|
||||
dot_token,
|
||||
reg_builder,
|
||||
reg_builder_paren,
|
||||
clock_domain,
|
||||
|
@ -451,15 +478,11 @@ impl HdlLetKindToTokens for HdlLetKindRegBuilder {
|
|||
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
ty: _,
|
||||
m,
|
||||
dot_token,
|
||||
reg_builder,
|
||||
reg_builder_paren,
|
||||
clock_domain,
|
||||
reset,
|
||||
} = self;
|
||||
m.to_tokens(tokens);
|
||||
dot_token.to_tokens(tokens);
|
||||
reg_builder.to_tokens(tokens);
|
||||
reg_builder_paren.surround(tokens, |_tokens| {});
|
||||
clock_domain.to_tokens(tokens);
|
||||
|
@ -470,18 +493,20 @@ impl HdlLetKindToTokens for HdlLetKindRegBuilder {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct HdlLetKindWire {
|
||||
pub(crate) ty: Option<(Token![:], Box<Type>)>,
|
||||
pub(crate) m: kw::m,
|
||||
pub(crate) dot_token: Token![.],
|
||||
pub(crate) wire: kw::wire,
|
||||
pub(crate) paren: Paren,
|
||||
pub(crate) ty_expr: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
impl ParseTypes<Self> for HdlLetKindWire {
|
||||
fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||
Ok(input.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
struct HdlLetKindWire<> {
|
||||
ty: Option<(Token![:], Box<Type>)>,
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
wire: kw::wire,
|
||||
paren: Paren,
|
||||
ty_expr: Option<Box<Expr>>,
|
||||
|
@ -499,14 +524,10 @@ impl HdlLetKindToTokens for HdlLetKindWire {
|
|||
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
ty: _,
|
||||
m,
|
||||
dot_token,
|
||||
wire,
|
||||
paren,
|
||||
ty_expr,
|
||||
} = self;
|
||||
m.to_tokens(tokens);
|
||||
dot_token.to_tokens(tokens);
|
||||
wire.to_tokens(tokens);
|
||||
paren.surround(tokens, |tokens| ty_expr.to_tokens(tokens));
|
||||
}
|
||||
|
@ -627,16 +648,18 @@ impl ToTokens for MemoryFn {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct HdlLetKindMemory {
|
||||
pub(crate) ty: Option<(Token![:], Box<Type>)>,
|
||||
pub(crate) m: kw::m,
|
||||
pub(crate) dot_token: Token![.],
|
||||
pub(crate) memory_fn: MemoryFn,
|
||||
}
|
||||
|
||||
impl ParseTypes<Self> for HdlLetKindMemory {
|
||||
fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||
Ok(input.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
struct HdlLetKindMemory<> {
|
||||
ty: Option<(Token![:], Box<Type>)>,
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
memory_fn: MemoryFn,
|
||||
}
|
||||
}
|
||||
|
@ -650,14 +673,7 @@ impl HdlLetKindToTokens for HdlLetKindMemory {
|
|||
}
|
||||
|
||||
fn expr_to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
ty: _,
|
||||
m,
|
||||
dot_token,
|
||||
memory_fn,
|
||||
} = self;
|
||||
m.to_tokens(tokens);
|
||||
dot_token.to_tokens(tokens);
|
||||
let Self { ty: _, memory_fn } = self;
|
||||
memory_fn.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
@ -667,22 +683,20 @@ impl HdlLetKindMemory {
|
|||
input: ParseStream,
|
||||
parsed_ty: Option<(Token![:], Box<Type>)>,
|
||||
_after_ty: Token![=],
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
m_dot: Option<(kw::m, Token![.])>,
|
||||
memory_fn_name: MemoryFnName,
|
||||
) -> syn::Result<Self> {
|
||||
check_empty_m_dot(m_dot, memory_fn_name)?;
|
||||
Ok(Self {
|
||||
ty: parsed_ty,
|
||||
m,
|
||||
dot_token,
|
||||
memory_fn: MemoryFn::parse_rest(input, memory_fn_name)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum HdlLetKind {
|
||||
IO(HdlLetKindIO),
|
||||
pub(crate) enum HdlLetKind<IOType = ParsedType> {
|
||||
IO(HdlLetKindIO<ModuleIOKind, IOType>),
|
||||
Instance(HdlLetKindInstance),
|
||||
RegBuilder(HdlLetKindRegBuilder),
|
||||
Wire(HdlLetKindWire),
|
||||
|
@ -690,8 +704,8 @@ pub(crate) enum HdlLetKind {
|
|||
}
|
||||
|
||||
impl_fold! {
|
||||
enum HdlLetKind<> {
|
||||
IO(HdlLetKindIO),
|
||||
enum HdlLetKind<IOType,> {
|
||||
IO(HdlLetKindIO<ModuleIOKind, IOType>),
|
||||
Instance(HdlLetKindInstance),
|
||||
RegBuilder(HdlLetKindRegBuilder),
|
||||
Wire(HdlLetKindWire),
|
||||
|
@ -699,6 +713,27 @@ impl_fold! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ParseTypes<I>, I> ParseTypes<HdlLetKind<I>> for HdlLetKind<T> {
|
||||
fn parse_types(
|
||||
input: &mut HdlLetKind<I>,
|
||||
parser: &mut TypesParser<'_>,
|
||||
) -> Result<Self, ParseFailed> {
|
||||
match input {
|
||||
HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO),
|
||||
HdlLetKind::Instance(input) => {
|
||||
ParseTypes::parse_types(input, parser).map(HdlLetKind::Instance)
|
||||
}
|
||||
HdlLetKind::RegBuilder(input) => {
|
||||
ParseTypes::parse_types(input, parser).map(HdlLetKind::RegBuilder)
|
||||
}
|
||||
HdlLetKind::Wire(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::Wire),
|
||||
HdlLetKind::Memory(input) => {
|
||||
ParseTypes::parse_types(input, parser).map(HdlLetKind::Memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parsed_ty_or_err(
|
||||
parsed_ty: Option<(Token![:], Box<Type>)>,
|
||||
after_ty: Token![=],
|
||||
|
@ -710,15 +745,15 @@ fn parsed_ty_or_err(
|
|||
}
|
||||
}
|
||||
|
||||
impl HdlLetKindIO {
|
||||
impl HdlLetKindIO<ModuleIOKind, Type> {
|
||||
fn rest_of_parse(
|
||||
input: ParseStream,
|
||||
parsed_ty: Option<(Token![:], Box<Type>)>,
|
||||
after_ty: Token![=],
|
||||
m: kw::m,
|
||||
dot_token: Token![.],
|
||||
m_dot: Option<(kw::m, Token![.])>,
|
||||
kind: ModuleIOKind,
|
||||
) -> syn::Result<Self> {
|
||||
let (m, dot_token) = unwrap_m_dot(m_dot, kind)?;
|
||||
let (colon_token, ty) = parsed_ty_or_err(parsed_ty, after_ty)?;
|
||||
let paren_contents;
|
||||
Ok(Self {
|
||||
|
@ -733,7 +768,36 @@ impl HdlLetKindIO {
|
|||
}
|
||||
}
|
||||
|
||||
impl HdlLetKindParse for HdlLetKind {
|
||||
fn check_empty_m_dot(m_dot: Option<(kw::m, Token![.])>, kind: impl ToTokens) -> syn::Result<()> {
|
||||
if let Some((m, dot_token)) = m_dot {
|
||||
Err(Error::new_spanned(
|
||||
quote! {#m #dot_token #kind},
|
||||
format_args!(
|
||||
"{} is a free function, not a method of ModuleBuilder: try removing the `m.`",
|
||||
kind.to_token_stream()
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_m_dot(
|
||||
m_dot: Option<(kw::m, Token![.])>,
|
||||
kind: impl ToTokens,
|
||||
) -> syn::Result<(kw::m, Token![.])> {
|
||||
m_dot.ok_or_else(|| {
|
||||
Error::new_spanned(
|
||||
&kind,
|
||||
format_args!(
|
||||
"{} is a ModuleBuilder method, not a free function: try prefixing it with `m.`",
|
||||
kind.to_token_stream()
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
impl HdlLetKindParse for HdlLetKind<Type> {
|
||||
type ParsedTy = Option<(Token![:], Box<Type>)>;
|
||||
|
||||
fn parse_ty(input: ParseStream) -> syn::Result<Self::ParsedTy> {
|
||||
|
@ -753,16 +817,20 @@ impl HdlLetKindParse for HdlLetKind {
|
|||
after_ty: Token![=],
|
||||
input: ParseStream,
|
||||
) -> syn::Result<Self> {
|
||||
let m = input.parse()?;
|
||||
let dot_token = input.parse()?;
|
||||
let m_dot = if input.peek(kw::m) && input.peek2(Token![.]) {
|
||||
let m = input.parse()?;
|
||||
let dot_token = input.parse()?;
|
||||
Some((m, dot_token))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let kind: LetFnKind = input.parse()?;
|
||||
match kind {
|
||||
LetFnKind::Input(input_token) => HdlLetKindIO::rest_of_parse(
|
||||
input,
|
||||
parsed_ty,
|
||||
after_ty,
|
||||
m,
|
||||
dot_token,
|
||||
m_dot,
|
||||
ModuleIOKind::Input(input_token),
|
||||
)
|
||||
.map(Self::IO),
|
||||
|
@ -770,8 +838,7 @@ impl HdlLetKindParse for HdlLetKind {
|
|||
input,
|
||||
parsed_ty,
|
||||
after_ty,
|
||||
m,
|
||||
dot_token,
|
||||
m_dot,
|
||||
ModuleIOKind::Output(output),
|
||||
)
|
||||
.map(Self::IO),
|
||||
|
@ -782,30 +849,23 @@ impl HdlLetKindParse for HdlLetKind {
|
|||
"type annotation not allowed for instance",
|
||||
));
|
||||
}
|
||||
check_empty_m_dot(m_dot, kind)?;
|
||||
let paren_contents;
|
||||
Ok(Self::Instance(HdlLetKindInstance {
|
||||
m,
|
||||
dot_token,
|
||||
instance,
|
||||
paren: parenthesized!(paren_contents in input),
|
||||
module: paren_contents.call(parse_single_fn_arg)?,
|
||||
}))
|
||||
}
|
||||
LetFnKind::RegBuilder((reg_builder,)) => HdlLetKindRegBuilder::rest_of_parse(
|
||||
input,
|
||||
parsed_ty,
|
||||
after_ty,
|
||||
m,
|
||||
dot_token,
|
||||
reg_builder,
|
||||
)
|
||||
.map(Self::RegBuilder),
|
||||
LetFnKind::RegBuilder((reg_builder,)) => {
|
||||
HdlLetKindRegBuilder::rest_of_parse(input, parsed_ty, after_ty, m_dot, reg_builder)
|
||||
.map(Self::RegBuilder)
|
||||
}
|
||||
LetFnKind::Wire((wire,)) => {
|
||||
check_empty_m_dot(m_dot, wire)?;
|
||||
let paren_contents;
|
||||
Ok(Self::Wire(HdlLetKindWire {
|
||||
ty: parsed_ty,
|
||||
m,
|
||||
dot_token,
|
||||
wire,
|
||||
paren: parenthesized!(paren_contents in input),
|
||||
ty_expr: paren_contents.call(parse_optional_fn_arg)?,
|
||||
|
@ -815,8 +875,7 @@ impl HdlLetKindParse for HdlLetKind {
|
|||
input,
|
||||
parsed_ty,
|
||||
after_ty,
|
||||
m,
|
||||
dot_token,
|
||||
m_dot,
|
||||
MemoryFnName::Memory(fn_name),
|
||||
)
|
||||
.map(Self::Memory),
|
||||
|
@ -824,8 +883,7 @@ impl HdlLetKindParse for HdlLetKind {
|
|||
input,
|
||||
parsed_ty,
|
||||
after_ty,
|
||||
m,
|
||||
dot_token,
|
||||
m_dot,
|
||||
MemoryFnName::MemoryArray(fn_name),
|
||||
)
|
||||
.map(Self::Memory),
|
||||
|
@ -833,8 +891,7 @@ impl HdlLetKindParse for HdlLetKind {
|
|||
input,
|
||||
parsed_ty,
|
||||
after_ty,
|
||||
m,
|
||||
dot_token,
|
||||
m_dot,
|
||||
MemoryFnName::MemoryWithInit(fn_name),
|
||||
)
|
||||
.map(Self::Memory),
|
||||
|
@ -878,6 +935,34 @@ with_debug_clone_and_fold! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ParseTypes<I>, I> ParseTypes<HdlLet<I>> for HdlLet<T> {
|
||||
fn parse_types(
|
||||
input: &mut HdlLet<I>,
|
||||
parser: &mut TypesParser<'_>,
|
||||
) -> Result<Self, ParseFailed> {
|
||||
let HdlLet {
|
||||
attrs,
|
||||
hdl_attr,
|
||||
let_token,
|
||||
mut_token,
|
||||
name,
|
||||
eq_token,
|
||||
kind,
|
||||
semi_token,
|
||||
} = input;
|
||||
Ok(Self {
|
||||
attrs: attrs.clone(),
|
||||
hdl_attr: hdl_attr.clone(),
|
||||
let_token: *let_token,
|
||||
mut_token: *mut_token,
|
||||
name: name.clone(),
|
||||
eq_token: *eq_token,
|
||||
kind: T::parse_types(kind, parser)?,
|
||||
semi_token: *semi_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Kind> HdlLet<Kind> {
|
||||
pub(crate) fn try_map<Kind2, E>(
|
||||
self,
|
||||
|
@ -1006,7 +1091,7 @@ fn wrap_ty_with_expr(ty: impl ToTokens) -> Type {
|
|||
fn unwrap_or_static_type(expr: Option<impl ToTokens>, span: Span) -> TokenStream {
|
||||
expr.map(ToTokens::into_token_stream).unwrap_or_else(|| {
|
||||
quote_spanned! {span=>
|
||||
::fayalite::ty::StaticType::static_type()
|
||||
::fayalite::ty::StaticType::TYPE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1026,14 +1111,15 @@ impl<T: ToString> ToTokens for ImplicitName<T> {
|
|||
}
|
||||
}
|
||||
|
||||
struct Visitor {
|
||||
struct Visitor<'a> {
|
||||
module_kind: ModuleKind,
|
||||
errors: Errors,
|
||||
io: Vec<ModuleIO>,
|
||||
block_depth: usize,
|
||||
parsed_generics: &'a ParsedGenerics,
|
||||
}
|
||||
|
||||
impl Visitor {
|
||||
impl Visitor<'_> {
|
||||
fn take_hdl_attr<T: Parse>(&mut self, attrs: &mut Vec<Attribute>) -> Option<HdlAttr<T>> {
|
||||
self.errors.unwrap_or(
|
||||
HdlAttr::parse_and_take_attr(attrs),
|
||||
|
@ -1086,7 +1172,7 @@ impl Visitor {
|
|||
parse_quote_spanned! {if_token.span=>
|
||||
#(#attrs)*
|
||||
{
|
||||
let mut __scope = m.if_(#cond);
|
||||
let mut __scope = ::fayalite::module::if_(#cond);
|
||||
let _: () = #then_branch;
|
||||
let mut __scope = __scope.else_();
|
||||
let _: () = #else_expr;
|
||||
|
@ -1096,7 +1182,7 @@ impl Visitor {
|
|||
parse_quote_spanned! {if_token.span=>
|
||||
#(#attrs)*
|
||||
{
|
||||
let mut __scope = m.if_(#cond);
|
||||
let mut __scope = ::fayalite::module::if_(#cond);
|
||||
let _: () = #then_branch;
|
||||
}
|
||||
}
|
||||
|
@ -1157,8 +1243,6 @@ impl Visitor {
|
|||
eq_token,
|
||||
kind:
|
||||
HdlLetKindInstance {
|
||||
m,
|
||||
dot_token,
|
||||
instance,
|
||||
paren,
|
||||
module,
|
||||
|
@ -1166,7 +1250,7 @@ impl Visitor {
|
|||
semi_token,
|
||||
} = hdl_let;
|
||||
self.require_normal_module(instance);
|
||||
let mut expr = quote! {#m #dot_token #instance};
|
||||
let mut expr = instance.to_token_stream();
|
||||
paren.surround(&mut expr, |expr| {
|
||||
let name_str = ImplicitName {
|
||||
name: &name,
|
||||
|
@ -1191,11 +1275,9 @@ impl Visitor {
|
|||
}
|
||||
fn process_hdl_let_reg_builder(&mut self, hdl_let: HdlLet<HdlLetKindRegBuilder>) -> Local {
|
||||
let name = &hdl_let.name;
|
||||
let m = hdl_let.kind.m;
|
||||
let dot = hdl_let.kind.dot_token;
|
||||
let reg_builder = hdl_let.kind.reg_builder;
|
||||
self.require_normal_module(reg_builder);
|
||||
let mut expr = quote! {#m #dot #reg_builder};
|
||||
let mut expr = reg_builder.to_token_stream();
|
||||
hdl_let.kind.reg_builder_paren.surround(&mut expr, |expr| {
|
||||
let name_str = ImplicitName {
|
||||
name,
|
||||
|
@ -1244,12 +1326,10 @@ impl Visitor {
|
|||
}
|
||||
fn process_hdl_let_wire(&mut self, hdl_let: HdlLet<HdlLetKindWire>) -> Local {
|
||||
let name = &hdl_let.name;
|
||||
let m = hdl_let.kind.m;
|
||||
let dot = hdl_let.kind.dot_token;
|
||||
let wire = hdl_let.kind.wire;
|
||||
self.require_normal_module(wire);
|
||||
let ty_expr = unwrap_or_static_type(hdl_let.kind.ty_expr.as_ref(), wire.span());
|
||||
let mut expr = quote! {#m #dot #wire};
|
||||
let mut expr = wire.to_token_stream();
|
||||
hdl_let.kind.paren.surround(&mut expr, |expr| {
|
||||
let name_str = ImplicitName {
|
||||
name,
|
||||
|
@ -1279,18 +1359,19 @@ impl Visitor {
|
|||
}
|
||||
fn process_hdl_let_memory(&mut self, hdl_let: HdlLet<HdlLetKindMemory>) -> Local {
|
||||
let name = &hdl_let.name;
|
||||
let m = hdl_let.kind.m;
|
||||
let dot = hdl_let.kind.dot_token;
|
||||
let memory_fn = hdl_let.kind.memory_fn;
|
||||
let memory_fn_name = memory_fn.name();
|
||||
self.require_normal_module(memory_fn_name);
|
||||
let mut expr = quote! {#m #dot #memory_fn_name};
|
||||
let mut expr = memory_fn_name.to_token_stream();
|
||||
let (paren, arg) = match memory_fn {
|
||||
MemoryFn::Memory {
|
||||
memory,
|
||||
paren,
|
||||
ty_expr,
|
||||
} => (paren, unwrap_or_static_type(ty_expr.as_ref(), memory.span())),
|
||||
} => (
|
||||
paren,
|
||||
unwrap_or_static_type(ty_expr.as_ref(), memory.span()),
|
||||
),
|
||||
MemoryFn::MemoryArray {
|
||||
memory_array,
|
||||
paren,
|
||||
|
@ -1377,16 +1458,17 @@ impl Visitor {
|
|||
let value: BigInt = self
|
||||
.errors
|
||||
.ok(base10_digits.parse().map_err(|e| Error::new(span, e)))?;
|
||||
let (negative, bytes) = match value.sign() {
|
||||
Sign::Minus => (true, value.magnitude().to_bytes_le()),
|
||||
Sign::NoSign => (false, vec![]),
|
||||
Sign::Plus => (false, value.magnitude().to_bytes_le()),
|
||||
let bytes = value.to_signed_bytes_le();
|
||||
let path = if signed {
|
||||
known_items::SInt(span).path
|
||||
} else {
|
||||
known_items::UInt(span).path
|
||||
};
|
||||
Some(parse_quote_spanned! {span=>
|
||||
::fayalite::int::make_int_literal::<#signed, #width>(
|
||||
#negative,
|
||||
<#path<#width> as ::fayalite::int::BoolOrIntType>::le_bytes_to_expr_wrapping(
|
||||
&[#(#bytes,)*],
|
||||
).to_int_expr()
|
||||
#width,
|
||||
)
|
||||
})
|
||||
}
|
||||
fn process_literal(&mut self, literal: ExprLit) -> Expr {
|
||||
|
@ -1449,7 +1531,7 @@ fn empty_let() -> Local {
|
|||
}
|
||||
}
|
||||
|
||||
impl Fold for Visitor {
|
||||
impl Fold for Visitor<'_> {
|
||||
fn fold_item(&mut self, item: Item) -> Item {
|
||||
// don't process item interiors
|
||||
item
|
||||
|
@ -1521,8 +1603,6 @@ impl Fold for Visitor {
|
|||
Repeat => process_hdl_repeat,
|
||||
Struct => process_hdl_struct,
|
||||
Tuple => process_hdl_tuple,
|
||||
Call => process_hdl_call,
|
||||
Path => process_hdl_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1536,11 +1616,16 @@ impl Fold for Visitor {
|
|||
Some(None) => return fold_local(self, let_stmt),
|
||||
Some(Some(HdlAttr { .. })) => {}
|
||||
};
|
||||
let hdl_let = syn::parse2::<HdlLet>(let_stmt.into_token_stream());
|
||||
let hdl_let = syn::parse2::<HdlLet<HdlLetKind<Type>>>(let_stmt.into_token_stream());
|
||||
let Some(hdl_let) = self.errors.ok(hdl_let) else {
|
||||
return empty_let();
|
||||
};
|
||||
let hdl_let = hdl_let.do_fold(self);
|
||||
let mut hdl_let = hdl_let.do_fold(self);
|
||||
let Ok(hdl_let) =
|
||||
TypesParser::run_with_errors(self.parsed_generics, &mut hdl_let, &mut self.errors)
|
||||
else {
|
||||
return empty_let();
|
||||
};
|
||||
self.process_hdl_let(hdl_let)
|
||||
}
|
||||
|
||||
|
@ -1563,12 +1648,14 @@ impl Fold for Visitor {
|
|||
pub(crate) fn transform_body(
|
||||
module_kind: ModuleKind,
|
||||
mut body: Box<Block>,
|
||||
parsed_generics: &ParsedGenerics,
|
||||
) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> {
|
||||
let mut visitor = Visitor {
|
||||
module_kind,
|
||||
errors: Errors::new(),
|
||||
io: vec![],
|
||||
block_depth: 0,
|
||||
parsed_generics,
|
||||
};
|
||||
*body = syn::fold::fold_block(&mut visitor, *body);
|
||||
visitor.errors.finish()?;
|
||||
|
|
|
@ -1,336 +1,13 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{module::transform_body::Visitor, options, Errors, HdlAttr, PairsIterExt};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt};
|
||||
use crate::{module::transform_body::Visitor, HdlAttr};
|
||||
use quote::{format_ident, quote_spanned};
|
||||
use syn::{
|
||||
parse::Nothing,
|
||||
parse_quote, parse_quote_spanned,
|
||||
punctuated::{Pair, Punctuated},
|
||||
spanned::Spanned,
|
||||
token::{Brace, Paren},
|
||||
Attribute, Expr, ExprArray, ExprCall, ExprGroup, ExprPath, ExprRepeat, ExprStruct, ExprTuple,
|
||||
FieldValue, Ident, Index, Member, Path, PathArguments, PathSegment, Token, TypePath,
|
||||
parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
|
||||
ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath,
|
||||
};
|
||||
|
||||
options! {
|
||||
#[options = AggregateLiteralOptions]
|
||||
#[no_ident_fragment]
|
||||
pub(crate) enum AggregateLiteralOption {
|
||||
Struct(struct_),
|
||||
Enum(enum_),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct StructOrEnumPath {
|
||||
pub(crate) ty: TypePath,
|
||||
pub(crate) variant: Option<(TypePath, Ident)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct SingleSegmentVariant {
|
||||
pub(crate) name: &'static str,
|
||||
pub(crate) make_type_path: fn(Span, &PathArguments) -> Path,
|
||||
}
|
||||
|
||||
impl StructOrEnumPath {
|
||||
pub(crate) const SINGLE_SEGMENT_VARIANTS: &'static [SingleSegmentVariant] = {
|
||||
fn make_option_type_path(span: Span, arguments: &PathArguments) -> Path {
|
||||
let arguments = if arguments.is_none() {
|
||||
quote_spanned! {span=>
|
||||
<_>
|
||||
}
|
||||
} else {
|
||||
arguments.to_token_stream()
|
||||
};
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::__std::option::Option #arguments
|
||||
}
|
||||
}
|
||||
fn make_result_type_path(span: Span, arguments: &PathArguments) -> Path {
|
||||
let arguments = if arguments.is_none() {
|
||||
quote_spanned! {span=>
|
||||
<_, _>
|
||||
}
|
||||
} else {
|
||||
arguments.to_token_stream()
|
||||
};
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::__std::result::Result #arguments
|
||||
}
|
||||
}
|
||||
&[
|
||||
SingleSegmentVariant {
|
||||
name: "Some",
|
||||
make_type_path: make_option_type_path,
|
||||
},
|
||||
SingleSegmentVariant {
|
||||
name: "None",
|
||||
make_type_path: make_option_type_path,
|
||||
},
|
||||
SingleSegmentVariant {
|
||||
name: "Ok",
|
||||
make_type_path: make_result_type_path,
|
||||
},
|
||||
SingleSegmentVariant {
|
||||
name: "Err",
|
||||
make_type_path: make_result_type_path,
|
||||
},
|
||||
]
|
||||
};
|
||||
pub(crate) fn new(
|
||||
errors: &mut Errors,
|
||||
path: TypePath,
|
||||
options: &AggregateLiteralOptions,
|
||||
) -> Result<Self, ()> {
|
||||
let Path {
|
||||
leading_colon,
|
||||
segments,
|
||||
} = &path.path;
|
||||
let qself_position = path.qself.as_ref().map(|qself| qself.position).unwrap_or(0);
|
||||
let variant_name = if qself_position < segments.len() {
|
||||
Some(segments.last().unwrap().ident.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let enum_type = 'guess_enum_type: {
|
||||
if options.enum_.is_some() {
|
||||
if let Some((struct_,)) = options.struct_ {
|
||||
errors.error(
|
||||
struct_,
|
||||
"can't specify both #[hdl(enum)] and #[hdl(struct)]",
|
||||
);
|
||||
}
|
||||
break 'guess_enum_type Some(None);
|
||||
}
|
||||
if options.struct_.is_some() {
|
||||
break 'guess_enum_type None;
|
||||
}
|
||||
if path.qself.is_none() && leading_colon.is_none() && segments.len() == 1 {
|
||||
let PathSegment { ident, arguments } = &segments[0];
|
||||
for &SingleSegmentVariant {
|
||||
name,
|
||||
make_type_path,
|
||||
} in Self::SINGLE_SEGMENT_VARIANTS
|
||||
{
|
||||
if ident == name {
|
||||
break 'guess_enum_type Some(Some(TypePath {
|
||||
qself: None,
|
||||
path: make_type_path(ident.span(), arguments),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
if segments.len() == qself_position + 2
|
||||
&& segments[qself_position + 1].arguments.is_none()
|
||||
&& (path.qself.is_some()
|
||||
|| segments[qself_position].ident.to_string().as_bytes()[0]
|
||||
.is_ascii_uppercase())
|
||||
{
|
||||
let mut ty = path.clone();
|
||||
ty.path.segments.pop();
|
||||
ty.path.segments.pop_punct();
|
||||
break 'guess_enum_type Some(Some(ty));
|
||||
}
|
||||
None
|
||||
};
|
||||
if let Some(enum_type) = enum_type {
|
||||
let ty = if let Some(enum_type) = enum_type {
|
||||
enum_type
|
||||
} else {
|
||||
if qself_position >= segments.len() {
|
||||
errors.error(path, "#[hdl]: can't figure out enum's type");
|
||||
return Err(());
|
||||
}
|
||||
let mut ty = path.clone();
|
||||
ty.path.segments.pop();
|
||||
ty.path.segments.pop_punct();
|
||||
ty
|
||||
};
|
||||
let Some(variant_name) = variant_name else {
|
||||
errors.error(path, "#[hdl]: can't figure out enum's variant name");
|
||||
return Err(());
|
||||
};
|
||||
Ok(Self {
|
||||
ty,
|
||||
variant: Some((path, variant_name)),
|
||||
})
|
||||
} else {
|
||||
Ok(Self {
|
||||
ty: path,
|
||||
variant: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum BraceOrParen {
|
||||
Brace(Brace),
|
||||
Paren(Paren),
|
||||
}
|
||||
|
||||
impl BraceOrParen {
|
||||
pub(crate) fn surround(self, tokens: &mut TokenStream, f: impl FnOnce(&mut TokenStream)) {
|
||||
match self {
|
||||
BraceOrParen::Brace(v) => v.surround(tokens, f),
|
||||
BraceOrParen::Paren(v) => v.surround(tokens, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct StructOrEnumLiteralField {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) member: Member,
|
||||
pub(crate) colon_token: Option<Token![:]>,
|
||||
pub(crate) expr: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct StructOrEnumLiteral {
|
||||
pub(crate) attrs: Vec<Attribute>,
|
||||
pub(crate) path: TypePath,
|
||||
pub(crate) brace_or_paren: BraceOrParen,
|
||||
pub(crate) fields: Punctuated<StructOrEnumLiteralField, Token![,]>,
|
||||
pub(crate) dot2_token: Option<Token![..]>,
|
||||
pub(crate) rest: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
impl StructOrEnumLiteral {
|
||||
pub(crate) fn map_field_exprs(self, mut f: impl FnMut(Expr) -> Expr) -> Self {
|
||||
self.map_fields(|mut field| {
|
||||
field.expr = f(field.expr);
|
||||
field
|
||||
})
|
||||
}
|
||||
pub(crate) fn map_fields(
|
||||
self,
|
||||
f: impl FnMut(StructOrEnumLiteralField) -> StructOrEnumLiteralField,
|
||||
) -> Self {
|
||||
let Self {
|
||||
attrs,
|
||||
path,
|
||||
brace_or_paren,
|
||||
fields,
|
||||
dot2_token,
|
||||
rest,
|
||||
} = self;
|
||||
let fields = fields.into_pairs().map_pair_value(f).collect();
|
||||
Self {
|
||||
attrs,
|
||||
path,
|
||||
brace_or_paren,
|
||||
fields,
|
||||
dot2_token,
|
||||
rest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExprStruct> for StructOrEnumLiteral {
|
||||
fn from(value: ExprStruct) -> Self {
|
||||
let ExprStruct {
|
||||
attrs,
|
||||
qself,
|
||||
path,
|
||||
brace_token,
|
||||
fields,
|
||||
dot2_token,
|
||||
rest,
|
||||
} = value;
|
||||
Self {
|
||||
attrs,
|
||||
path: TypePath { qself, path },
|
||||
brace_or_paren: BraceOrParen::Brace(brace_token),
|
||||
fields: fields
|
||||
.into_pairs()
|
||||
.map_pair_value(
|
||||
|FieldValue {
|
||||
attrs,
|
||||
member,
|
||||
colon_token,
|
||||
expr,
|
||||
}| StructOrEnumLiteralField {
|
||||
attrs,
|
||||
member,
|
||||
colon_token,
|
||||
expr,
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
dot2_token,
|
||||
rest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_to_member(expr: &Expr) -> Option<Member> {
|
||||
syn::parse2(expr.to_token_stream()).ok()
|
||||
}
|
||||
|
||||
impl ToTokens for StructOrEnumLiteral {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
attrs,
|
||||
path,
|
||||
brace_or_paren,
|
||||
fields,
|
||||
dot2_token,
|
||||
rest,
|
||||
} = self;
|
||||
tokens.append_all(attrs);
|
||||
path.to_tokens(tokens);
|
||||
brace_or_paren.surround(tokens, |tokens| {
|
||||
match brace_or_paren {
|
||||
BraceOrParen::Brace(_) => {
|
||||
for (
|
||||
StructOrEnumLiteralField {
|
||||
attrs,
|
||||
member,
|
||||
mut colon_token,
|
||||
expr,
|
||||
},
|
||||
comma,
|
||||
) in fields.pairs().map(|v| v.into_tuple())
|
||||
{
|
||||
tokens.append_all(attrs);
|
||||
if Some(member) != expr_to_member(expr).as_ref() {
|
||||
colon_token = Some(<Token![:]>::default());
|
||||
}
|
||||
member.to_tokens(tokens);
|
||||
colon_token.to_tokens(tokens);
|
||||
expr.to_tokens(tokens);
|
||||
comma.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
BraceOrParen::Paren(_) => {
|
||||
for (
|
||||
StructOrEnumLiteralField {
|
||||
attrs,
|
||||
member: _,
|
||||
colon_token: _,
|
||||
expr,
|
||||
},
|
||||
comma,
|
||||
) in fields.pairs().map(|v| v.into_tuple())
|
||||
{
|
||||
tokens.append_all(attrs);
|
||||
expr.to_tokens(tokens);
|
||||
comma.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(rest) = rest {
|
||||
dot2_token.unwrap_or_default().to_tokens(tokens);
|
||||
rest.to_tokens(tokens);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor {
|
||||
impl Visitor<'_> {
|
||||
pub(crate) fn process_hdl_array(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
|
@ -356,100 +33,61 @@ impl Visitor {
|
|||
};
|
||||
parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)}
|
||||
}
|
||||
pub(crate) fn process_struct_enum(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<AggregateLiteralOptions>,
|
||||
mut literal: StructOrEnumLiteral,
|
||||
) -> Expr {
|
||||
let span = hdl_attr.hdl.span;
|
||||
if let Some(rest) = literal.rest.take() {
|
||||
self.errors
|
||||
.error(rest, "#[hdl] struct functional update syntax not supported");
|
||||
}
|
||||
let mut next_var = 0usize;
|
||||
let mut new_var = || -> Ident {
|
||||
let retval = format_ident!("__v{}", next_var, span = span);
|
||||
next_var += 1;
|
||||
retval
|
||||
};
|
||||
let infallible_var = new_var();
|
||||
let retval_var = new_var();
|
||||
let mut lets = vec![];
|
||||
let mut build_steps = vec![];
|
||||
let literal = literal.map_field_exprs(|expr| {
|
||||
let field_var = new_var();
|
||||
lets.push(quote_spanned! {span=>
|
||||
let #field_var = ::fayalite::expr::ToExpr::to_expr(&#expr);
|
||||
});
|
||||
parse_quote! { #field_var }
|
||||
});
|
||||
let Ok(StructOrEnumPath { ty, variant }) =
|
||||
StructOrEnumPath::new(&mut self.errors, literal.path.clone(), &hdl_attr.body)
|
||||
else {
|
||||
return parse_quote_spanned! {span=>
|
||||
{}
|
||||
};
|
||||
};
|
||||
for StructOrEnumLiteralField {
|
||||
attrs: _,
|
||||
member,
|
||||
colon_token: _,
|
||||
expr,
|
||||
} in literal.fields.iter()
|
||||
{
|
||||
let field_fn = format_ident!("field_{}", member);
|
||||
build_steps.push(quote_spanned! {span=>
|
||||
let #retval_var = #retval_var.#field_fn(#expr);
|
||||
});
|
||||
}
|
||||
let check_literal = literal.map_field_exprs(|expr| {
|
||||
parse_quote_spanned! {span=>
|
||||
::fayalite::expr::value_from_expr_type(#expr, #infallible_var)
|
||||
}
|
||||
});
|
||||
let make_expr_fn = if let Some((_variant_path, variant_ident)) = &variant {
|
||||
let variant_fn = format_ident!("variant_{}", variant_ident);
|
||||
build_steps.push(quote_spanned! {span=>
|
||||
let #retval_var = #retval_var.#variant_fn();
|
||||
});
|
||||
quote_spanned! {span=>
|
||||
::fayalite::expr::make_enum_expr
|
||||
}
|
||||
} else {
|
||||
build_steps.push(quote_spanned! {span=>
|
||||
let #retval_var = #retval_var.build();
|
||||
});
|
||||
quote_spanned! {span=>
|
||||
::fayalite::expr::make_bundle_expr
|
||||
}
|
||||
};
|
||||
let variant_or_type =
|
||||
variant.map_or_else(|| ty.clone(), |(variant_path, _variant_ident)| variant_path);
|
||||
parse_quote_spanned! {span=>
|
||||
{
|
||||
#(#lets)*
|
||||
#make_expr_fn::<#ty>(|#infallible_var| {
|
||||
let #retval_var = #check_literal;
|
||||
#[allow(unreachable_code)]
|
||||
match #retval_var {
|
||||
#variant_or_type { .. } => #retval_var,
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => match #infallible_var {},
|
||||
}
|
||||
}, |#retval_var| {
|
||||
#(#build_steps)*
|
||||
#retval_var
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_struct(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<AggregateLiteralOptions>,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
expr_struct: ExprStruct,
|
||||
) -> Expr {
|
||||
self.require_normal_module(&hdl_attr);
|
||||
self.process_struct_enum(hdl_attr, expr_struct.into())
|
||||
let name_span = expr_struct.path.segments.last().unwrap().ident.span();
|
||||
let builder_ident = format_ident!("__builder", span = name_span);
|
||||
let empty_builder = if expr_struct.qself.is_some()
|
||||
|| expr_struct
|
||||
.path
|
||||
.segments
|
||||
.iter()
|
||||
.any(|seg| !seg.arguments.is_none())
|
||||
{
|
||||
let ty = TypePath {
|
||||
qself: expr_struct.qself,
|
||||
path: expr_struct.path,
|
||||
};
|
||||
let builder_ty = quote_spanned! {name_span=>
|
||||
<#ty as ::fayalite::bundle::BundleType>::Builder
|
||||
};
|
||||
quote_spanned! {name_span=>
|
||||
<#builder_ty as ::fayalite::__std::default::Default>::default()
|
||||
}
|
||||
} else {
|
||||
let path = ExprPath {
|
||||
attrs: vec![],
|
||||
qself: expr_struct.qself,
|
||||
path: expr_struct.path,
|
||||
};
|
||||
quote_spanned! {name_span=>
|
||||
#path::__bundle_builder()
|
||||
}
|
||||
};
|
||||
let field_calls = Vec::from_iter(expr_struct.fields.iter().map(
|
||||
|FieldValue {
|
||||
attrs: _,
|
||||
member,
|
||||
colon_token: _,
|
||||
expr,
|
||||
}| {
|
||||
let field_fn = format_ident!("field_{}", member);
|
||||
quote_spanned! {member.span()=>
|
||||
let #builder_ident = #builder_ident.#field_fn(#expr);
|
||||
}
|
||||
},
|
||||
));
|
||||
parse_quote_spanned! {name_span=>
|
||||
{
|
||||
let #builder_ident = #empty_builder;
|
||||
#(#field_calls)*
|
||||
::fayalite::expr::ToExpr::to_expr(&#builder_ident)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_tuple(
|
||||
&mut self,
|
||||
|
@ -461,80 +99,4 @@ impl Visitor {
|
|||
::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_path(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<Nothing>,
|
||||
expr_path: ExprPath,
|
||||
) -> Expr {
|
||||
self.require_normal_module(hdl_attr);
|
||||
parse_quote_spanned! {expr_path.span()=>
|
||||
::fayalite::expr::ToExpr::to_expr(&#expr_path)
|
||||
}
|
||||
}
|
||||
pub(crate) fn process_hdl_call(
|
||||
&mut self,
|
||||
hdl_attr: HdlAttr<AggregateLiteralOptions>,
|
||||
expr_call: ExprCall,
|
||||
) -> Expr {
|
||||
self.require_normal_module(&hdl_attr);
|
||||
let ExprCall {
|
||||
attrs: mut literal_attrs,
|
||||
func,
|
||||
paren_token,
|
||||
args,
|
||||
} = expr_call;
|
||||
let mut path_expr = *func;
|
||||
let path = loop {
|
||||
break match path_expr {
|
||||
Expr::Group(ExprGroup {
|
||||
attrs,
|
||||
group_token: _,
|
||||
expr,
|
||||
}) => {
|
||||
literal_attrs.extend(attrs);
|
||||
path_expr = *expr;
|
||||
continue;
|
||||
}
|
||||
Expr::Path(ExprPath { attrs, qself, path }) => {
|
||||
literal_attrs.extend(attrs);
|
||||
TypePath { qself, path }
|
||||
}
|
||||
_ => {
|
||||
self.errors.error(&path_expr, "missing tuple struct's name");
|
||||
return parse_quote_spanned! {path_expr.span()=>
|
||||
{}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
let fields = args
|
||||
.into_pairs()
|
||||
.enumerate()
|
||||
.map(|(index, p)| {
|
||||
let (expr, comma) = p.into_tuple();
|
||||
let mut index = Index::from(index);
|
||||
index.span = hdl_attr.hdl.span;
|
||||
Pair::new(
|
||||
StructOrEnumLiteralField {
|
||||
attrs: vec![],
|
||||
member: Member::Unnamed(index),
|
||||
colon_token: None,
|
||||
expr,
|
||||
},
|
||||
comma,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
self.process_struct_enum(
|
||||
hdl_attr,
|
||||
StructOrEnumLiteral {
|
||||
attrs: literal_attrs,
|
||||
path,
|
||||
brace_or_paren: BraceOrParen::Paren(paren_token),
|
||||
fields,
|
||||
dot2_token: None,
|
||||
rest: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,20 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
fold::impl_fold,
|
||||
module::transform_body::{
|
||||
expand_aggregate_literals::{AggregateLiteralOptions, StructOrEnumPath},
|
||||
with_debug_clone_and_fold, Visitor,
|
||||
},
|
||||
module::transform_body::{with_debug_clone_and_fold, Visitor},
|
||||
Errors, HdlAttr, PairsIterExt,
|
||||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{format_ident, ToTokens, TokenStreamExt};
|
||||
use syn::{
|
||||
fold::{fold_arm, fold_expr_match, fold_pat, Fold},
|
||||
parse::Nothing,
|
||||
parse_quote_spanned,
|
||||
punctuated::{Pair, Punctuated},
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned,
|
||||
token::{Brace, Paren},
|
||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Index, Member, Pat, PatIdent, PatOr,
|
||||
PatParen, PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, Token, TypePath,
|
||||
Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Member, Pat, PatIdent, PatOr, PatParen,
|
||||
PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, PathSegment, Token, TypePath,
|
||||
};
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
|
@ -81,7 +78,7 @@ impl ToTokens for MatchPatWild {
|
|||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatStructField<> {
|
||||
member: Member,
|
||||
field_name: Ident,
|
||||
colon_token: Option<Token![:]>,
|
||||
pat: MatchPatSimple,
|
||||
}
|
||||
|
@ -90,12 +87,19 @@ with_debug_clone_and_fold! {
|
|||
impl ToTokens for MatchPatStructField {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
member,
|
||||
field_name,
|
||||
colon_token,
|
||||
pat,
|
||||
} = self;
|
||||
member.to_tokens(tokens);
|
||||
colon_token.to_tokens(tokens);
|
||||
field_name.to_tokens(tokens);
|
||||
if let (None, MatchPatSimple::Binding(MatchPatBinding { ident })) = (colon_token, pat) {
|
||||
if field_name == ident {
|
||||
return;
|
||||
}
|
||||
}
|
||||
colon_token
|
||||
.unwrap_or_else(|| Token))
|
||||
.to_tokens(tokens);
|
||||
pat.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
@ -108,8 +112,16 @@ impl MatchPatStructField {
|
|||
colon_token,
|
||||
pat,
|
||||
} = field_pat;
|
||||
let field_name = if let Member::Named(field_name) = member {
|
||||
field_name
|
||||
} else {
|
||||
state
|
||||
.errors
|
||||
.error(&member, "field name must not be a number");
|
||||
format_ident!("_{}", member)
|
||||
};
|
||||
Ok(Self {
|
||||
member,
|
||||
field_name,
|
||||
colon_token,
|
||||
pat: MatchPatSimple::parse(state, *pat)?,
|
||||
})
|
||||
|
@ -118,7 +130,7 @@ impl MatchPatStructField {
|
|||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatStruct<> {
|
||||
resolved_path: Path,
|
||||
path: Path,
|
||||
brace_token: Brace,
|
||||
fields: Punctuated<MatchPatStructField, Token![,]>,
|
||||
rest: Option<Token![..]>,
|
||||
|
@ -128,12 +140,12 @@ with_debug_clone_and_fold! {
|
|||
impl ToTokens for MatchPatStruct {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
resolved_path,
|
||||
path,
|
||||
brace_token,
|
||||
fields,
|
||||
rest,
|
||||
} = self;
|
||||
resolved_path.to_tokens(tokens);
|
||||
path.to_tokens(tokens);
|
||||
brace_token.surround(tokens, |tokens| {
|
||||
fields.to_tokens(tokens);
|
||||
rest.to_tokens(tokens);
|
||||
|
@ -141,6 +153,30 @@ impl ToTokens for MatchPatStruct {
|
|||
}
|
||||
}
|
||||
|
||||
with_debug_clone_and_fold! {
|
||||
struct MatchPatEnumVariant<> {
|
||||
variant_path: Path,
|
||||
enum_path: Path,
|
||||
variant_name: Ident,
|
||||
field: Option<(Paren, MatchPatSimple)>,
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPatEnumVariant {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
variant_path,
|
||||
enum_path: _,
|
||||
variant_name: _,
|
||||
field,
|
||||
} = self;
|
||||
variant_path.to_tokens(tokens);
|
||||
if let Some((paren_token, field)) = field {
|
||||
paren_token.surround(tokens, |tokens| field.to_tokens(tokens));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum MatchPatSimple {
|
||||
Paren(MatchPatParen<MatchPatSimple>),
|
||||
|
@ -169,21 +205,70 @@ impl ToTokens for MatchPatSimple {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_pat_ident_a_struct_or_enum_name(ident: &Ident) -> bool {
|
||||
ident
|
||||
.to_string()
|
||||
.starts_with(|ch: char| ch.is_ascii_uppercase())
|
||||
struct EnumPath {
|
||||
variant_path: Path,
|
||||
enum_path: Path,
|
||||
variant_name: Ident,
|
||||
}
|
||||
|
||||
fn parse_enum_path(variant_path: TypePath) -> Result<EnumPath, TypePath> {
|
||||
let TypePath {
|
||||
qself: None,
|
||||
path: variant_path,
|
||||
} = variant_path
|
||||
else {
|
||||
return Err(variant_path);
|
||||
};
|
||||
if variant_path.is_ident("HdlNone") || variant_path.is_ident("HdlSome") {
|
||||
let ident = variant_path.get_ident().unwrap();
|
||||
return Ok(EnumPath {
|
||||
enum_path: parse_quote_spanned! {ident.span()=>
|
||||
::fayalite::enum_::HdlOption::<_>
|
||||
},
|
||||
variant_name: ident.clone(),
|
||||
variant_path,
|
||||
});
|
||||
}
|
||||
if variant_path.segments.len() < 2 {
|
||||
return Err(TypePath {
|
||||
qself: None,
|
||||
path: variant_path,
|
||||
});
|
||||
}
|
||||
let mut enum_path = variant_path.clone();
|
||||
let PathSegment {
|
||||
ident: variant_name,
|
||||
arguments,
|
||||
} = enum_path.segments.pop().unwrap().into_value();
|
||||
if !arguments.is_none() {
|
||||
return Err(TypePath {
|
||||
qself: None,
|
||||
path: variant_path,
|
||||
});
|
||||
}
|
||||
enum_path.segments.pop_punct();
|
||||
Ok(EnumPath {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_enum_ident(ident: Ident) -> Result<EnumPath, Ident> {
|
||||
parse_enum_path(TypePath {
|
||||
qself: None,
|
||||
path: ident.into(),
|
||||
})
|
||||
.map_err(|p| p.path.segments.into_iter().next().unwrap().ident)
|
||||
}
|
||||
|
||||
trait ParseMatchPat: Sized {
|
||||
fn simple(v: MatchPatSimple) -> Self;
|
||||
fn or(v: MatchPatOr<Self>) -> Self;
|
||||
fn paren(v: MatchPatParen<Self>) -> Self;
|
||||
fn struct_(
|
||||
state: &mut HdlMatchParseState<'_>,
|
||||
v: MatchPatStruct,
|
||||
struct_error_spanned: &dyn ToTokens,
|
||||
) -> Result<Self, ()>;
|
||||
fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result<Self, ()>;
|
||||
fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant)
|
||||
-> Result<Self, ()>;
|
||||
fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result<Self, ()> {
|
||||
match pat {
|
||||
Pat::Ident(PatIdent {
|
||||
|
@ -208,26 +293,23 @@ trait ParseMatchPat: Sized {
|
|||
.errors
|
||||
.error(at_token, "@ not allowed in #[hdl] patterns");
|
||||
}
|
||||
if is_pat_ident_a_struct_or_enum_name(&ident) {
|
||||
let ident_span = ident.span();
|
||||
let resolved_path = state.resolve_enum_struct_path(TypePath {
|
||||
qself: None,
|
||||
path: ident.clone().into(),
|
||||
})?;
|
||||
Self::struct_(
|
||||
match parse_enum_ident(ident) {
|
||||
Ok(EnumPath {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
}) => Self::enum_variant(
|
||||
state,
|
||||
MatchPatStruct {
|
||||
resolved_path,
|
||||
brace_token: Brace(ident_span),
|
||||
fields: Punctuated::new(),
|
||||
rest: None,
|
||||
MatchPatEnumVariant {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
&ident,
|
||||
)
|
||||
} else {
|
||||
Ok(Self::simple(MatchPatSimple::Binding(MatchPatBinding {
|
||||
),
|
||||
Err(ident) => Ok(Self::simple(MatchPatSimple::Binding(MatchPatBinding {
|
||||
ident,
|
||||
})))
|
||||
}))),
|
||||
}
|
||||
}
|
||||
Pat::Or(PatOr {
|
||||
|
@ -254,18 +336,21 @@ trait ParseMatchPat: Sized {
|
|||
qself,
|
||||
path,
|
||||
}) => {
|
||||
let path = TypePath { qself, path };
|
||||
let path_span = path.span();
|
||||
let resolved_path = state.resolve_enum_struct_path(path.clone())?;
|
||||
Self::struct_(
|
||||
let EnumPath {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
} = parse_enum_path(TypePath { qself, path }).map_err(|path| {
|
||||
state.errors.error(path, "unsupported enum variant path");
|
||||
})?;
|
||||
Self::enum_variant(
|
||||
state,
|
||||
MatchPatStruct {
|
||||
resolved_path,
|
||||
brace_token: Brace(path_span),
|
||||
fields: Punctuated::new(),
|
||||
rest: None,
|
||||
MatchPatEnumVariant {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: None,
|
||||
},
|
||||
&path,
|
||||
)
|
||||
}
|
||||
Pat::Struct(PatStruct {
|
||||
|
@ -282,12 +367,16 @@ trait ParseMatchPat: Sized {
|
|||
MatchPatStructField::parse(state, field_pat).ok()
|
||||
})
|
||||
.collect();
|
||||
let path = TypePath { qself, path };
|
||||
let resolved_path = state.resolve_enum_struct_path(path.clone())?;
|
||||
if qself.is_some() {
|
||||
state
|
||||
.errors
|
||||
.error(TypePath { qself, path }, "unsupported struct path");
|
||||
return Err(());
|
||||
}
|
||||
Self::struct_(
|
||||
state,
|
||||
MatchPatStruct {
|
||||
resolved_path,
|
||||
path,
|
||||
brace_token,
|
||||
fields,
|
||||
rest: rest.map(
|
||||
|
@ -297,7 +386,6 @@ trait ParseMatchPat: Sized {
|
|||
}| dot2_token,
|
||||
),
|
||||
},
|
||||
&path,
|
||||
)
|
||||
}
|
||||
Pat::TupleStruct(PatTupleStruct {
|
||||
|
@ -307,45 +395,44 @@ trait ParseMatchPat: Sized {
|
|||
paren_token,
|
||||
mut elems,
|
||||
}) => {
|
||||
let rest = if let Some(&Pat::Rest(PatRest {
|
||||
attrs: _,
|
||||
dot2_token,
|
||||
})) = elems.last()
|
||||
{
|
||||
elems.pop();
|
||||
Some(dot2_token)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let fields = elems
|
||||
.into_pairs()
|
||||
.enumerate()
|
||||
.filter_map(|(index, pair)| {
|
||||
let (pat, punct) = pair.into_tuple();
|
||||
let pat = MatchPatSimple::parse(state, pat).ok()?;
|
||||
let mut index = Index::from(index);
|
||||
index.span = state.span;
|
||||
let field = MatchPatStructField {
|
||||
member: index.into(),
|
||||
colon_token: Some(Token),
|
||||
pat,
|
||||
};
|
||||
Some(Pair::new(field, punct))
|
||||
let EnumPath {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
} = parse_enum_path(TypePath { qself, path }).map_err(|path| {
|
||||
state.errors.error(path, "unsupported enum variant path");
|
||||
})?;
|
||||
if elems.is_empty() {
|
||||
let mut tokens = TokenStream::new();
|
||||
paren_token.surround(&mut tokens, |_| {});
|
||||
state.errors.error(
|
||||
tokens,
|
||||
"field-less enum variants must not be matched using parenthesis",
|
||||
);
|
||||
}
|
||||
if elems.len() != 1 {
|
||||
state.errors.error(
|
||||
variant_path,
|
||||
"enum variant pattern must have exactly one field",
|
||||
);
|
||||
return Err(());
|
||||
}
|
||||
let field = elems.pop().unwrap().into_value();
|
||||
let field = if let Pat::Rest(rest) = field {
|
||||
MatchPatSimple::Wild(MatchPatWild {
|
||||
underscore_token: Token),
|
||||
})
|
||||
.collect();
|
||||
let path = TypePath { qself, path };
|
||||
let resolved_path = state.resolve_enum_struct_path(path.clone())?;
|
||||
Self::struct_(
|
||||
} else {
|
||||
MatchPatSimple::parse(state, field)?
|
||||
};
|
||||
Self::enum_variant(
|
||||
state,
|
||||
MatchPatStruct {
|
||||
resolved_path,
|
||||
brace_token: Brace {
|
||||
span: paren_token.span,
|
||||
},
|
||||
fields,
|
||||
rest,
|
||||
MatchPatEnumVariant {
|
||||
variant_path,
|
||||
enum_path,
|
||||
variant_name,
|
||||
field: Some((paren_token, field)),
|
||||
},
|
||||
&path,
|
||||
)
|
||||
}
|
||||
Pat::Rest(_) => {
|
||||
|
@ -387,14 +474,21 @@ impl ParseMatchPat for MatchPatSimple {
|
|||
Self::Paren(v)
|
||||
}
|
||||
|
||||
fn struct_(
|
||||
fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result<Self, ()> {
|
||||
state.errors.error(
|
||||
v.path,
|
||||
"matching structs is not yet implemented inside structs/enums in #[hdl] patterns",
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn enum_variant(
|
||||
state: &mut HdlMatchParseState<'_>,
|
||||
_v: MatchPatStruct,
|
||||
struct_error_spanned: &dyn ToTokens,
|
||||
v: MatchPatEnumVariant,
|
||||
) -> Result<Self, ()> {
|
||||
state.errors.error(
|
||||
struct_error_spanned,
|
||||
"not yet implemented inside structs/enums in #[hdl] patterns",
|
||||
v.variant_path,
|
||||
"matching enum variants is not yet implemented inside structs/enums in #[hdl] patterns",
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
|
@ -406,6 +500,7 @@ enum MatchPat {
|
|||
Or(MatchPatOr<MatchPat>),
|
||||
Paren(MatchPatParen<MatchPat>),
|
||||
Struct(MatchPatStruct),
|
||||
EnumVariant(MatchPatEnumVariant),
|
||||
}
|
||||
|
||||
impl_fold! {
|
||||
|
@ -414,6 +509,7 @@ impl_fold! {
|
|||
Or(MatchPatOr<MatchPat>),
|
||||
Paren(MatchPatParen<MatchPat>),
|
||||
Struct(MatchPatStruct),
|
||||
EnumVariant(MatchPatEnumVariant),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,13 +526,16 @@ impl ParseMatchPat for MatchPat {
|
|||
Self::Paren(v)
|
||||
}
|
||||
|
||||
fn struct_(
|
||||
_state: &mut HdlMatchParseState<'_>,
|
||||
v: MatchPatStruct,
|
||||
_struct_error_spanned: &dyn ToTokens,
|
||||
) -> Result<Self, ()> {
|
||||
fn struct_(_state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result<Self, ()> {
|
||||
Ok(Self::Struct(v))
|
||||
}
|
||||
|
||||
fn enum_variant(
|
||||
_state: &mut HdlMatchParseState<'_>,
|
||||
v: MatchPatEnumVariant,
|
||||
) -> Result<Self, ()> {
|
||||
Ok(Self::EnumVariant(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MatchPat {
|
||||
|
@ -446,6 +545,7 @@ impl ToTokens for MatchPat {
|
|||
Self::Or(v) => v.to_tokens(tokens),
|
||||
Self::Paren(v) => v.to_tokens(tokens),
|
||||
Self::Struct(v) => v.to_tokens(tokens),
|
||||
Self::EnumVariant(v) => v.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -511,23 +611,58 @@ impl Fold for RewriteAsCheckMatch {
|
|||
i.colon_token = Some(Token));
|
||||
i
|
||||
}
|
||||
fn fold_pat(&mut self, i: Pat) -> Pat {
|
||||
match i {
|
||||
Pat::Ident(PatIdent {
|
||||
attrs,
|
||||
by_ref,
|
||||
mutability,
|
||||
ident,
|
||||
subpat: None,
|
||||
}) if is_pat_ident_a_struct_or_enum_name(&ident) => {
|
||||
parse_quote_spanned! {ident.span()=>
|
||||
#(#attrs)*
|
||||
#by_ref
|
||||
#mutability
|
||||
#ident {}
|
||||
fn fold_pat(&mut self, pat: Pat) -> Pat {
|
||||
match pat {
|
||||
Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) {
|
||||
Ok(EnumPath {
|
||||
variant_path: _,
|
||||
enum_path,
|
||||
variant_name,
|
||||
}) => parse_quote_spanned! {self.span=>
|
||||
__MatchTy::<#enum_path>::#variant_name {}
|
||||
},
|
||||
Err(ident) => {
|
||||
pat_ident.ident = ident;
|
||||
Pat::Ident(self.fold_pat_ident(pat_ident))
|
||||
}
|
||||
}
|
||||
_ => fold_pat(self, i),
|
||||
},
|
||||
Pat::TupleStruct(PatTupleStruct {
|
||||
attrs,
|
||||
qself,
|
||||
path,
|
||||
paren_token,
|
||||
elems,
|
||||
}) => match parse_enum_path(TypePath { qself, path }) {
|
||||
Ok(EnumPath {
|
||||
variant_path: _,
|
||||
enum_path,
|
||||
variant_name,
|
||||
}) => {
|
||||
let path = parse_quote_spanned! {self.span=>
|
||||
__MatchTy::<#enum_path>::#variant_name
|
||||
};
|
||||
let elems = Punctuated::from_iter(
|
||||
elems.into_pairs().map_pair_value(|p| fold_pat(self, p)),
|
||||
);
|
||||
Pat::TupleStruct(PatTupleStruct {
|
||||
attrs,
|
||||
qself: None,
|
||||
path,
|
||||
paren_token,
|
||||
elems,
|
||||
})
|
||||
}
|
||||
Err(TypePath { qself, path }) => {
|
||||
Pat::TupleStruct(self.fold_pat_tuple_struct(PatTupleStruct {
|
||||
attrs,
|
||||
qself,
|
||||
path,
|
||||
paren_token,
|
||||
elems,
|
||||
}))
|
||||
}
|
||||
},
|
||||
_ => fold_pat(self, pat),
|
||||
}
|
||||
}
|
||||
fn fold_pat_ident(&mut self, mut i: PatIdent) -> PatIdent {
|
||||
|
@ -556,26 +691,9 @@ impl Fold for RewriteAsCheckMatch {
|
|||
|
||||
struct HdlMatchParseState<'a> {
|
||||
errors: &'a mut Errors,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl HdlMatchParseState<'_> {
|
||||
fn resolve_enum_struct_path(&mut self, path: TypePath) -> Result<Path, ()> {
|
||||
let StructOrEnumPath { ty, variant } =
|
||||
StructOrEnumPath::new(self.errors, path, &AggregateLiteralOptions::default())?;
|
||||
Ok(if let Some((_variant_path, variant_name)) = variant {
|
||||
parse_quote_spanned! {self.span=>
|
||||
__MatchTy::<#ty>::#variant_name
|
||||
}
|
||||
} else {
|
||||
parse_quote_spanned! {self.span=>
|
||||
__MatchTy::<#ty>
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor {
|
||||
impl Visitor<'_> {
|
||||
pub(crate) fn process_hdl_match(
|
||||
&mut self,
|
||||
_hdl_attr: HdlAttr<Nothing>,
|
||||
|
@ -593,22 +711,20 @@ impl Visitor {
|
|||
self.require_normal_module(match_token);
|
||||
let mut state = HdlMatchParseState {
|
||||
errors: &mut self.errors,
|
||||
span,
|
||||
};
|
||||
let arms = Vec::from_iter(
|
||||
arms.into_iter()
|
||||
.filter_map(|arm| MatchArm::parse(&mut state, arm).ok()),
|
||||
);
|
||||
parse_quote_spanned! {span=>
|
||||
let expr = quote::quote_spanned! {span=>
|
||||
{
|
||||
type __MatchTy<V> =
|
||||
<<V as ::fayalite::expr::ToExpr>::Type as ::fayalite::ty::Type>::MatchVariant;
|
||||
type __MatchTy<T> = <T as ::fayalite::ty::Type>::MatchVariant;
|
||||
let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr));
|
||||
::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| {
|
||||
#[allow(unused_variables)]
|
||||
#check_match
|
||||
});
|
||||
for __match_variant in m.match_(__match_expr) {
|
||||
for __match_variant in ::fayalite::module::match_(__match_expr) {
|
||||
let (__match_variant, __scope) =
|
||||
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
|
||||
__match_variant,
|
||||
|
@ -618,6 +734,8 @@ impl Visitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("{}", expr);
|
||||
syn::parse2(expr).unwrap()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue