support #[hdl] on functions -- enables #[hdl] usage in function body

This commit is contained in:
Jacob Lifshay 2024-09-20 18:42:24 -07:00
parent a8c804ef4a
commit ff94dda922
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
9 changed files with 341 additions and 156 deletions

View file

@ -925,7 +925,7 @@ with_debug_clone_and_fold! {
#[allow(dead_code)]
pub(crate) struct HdlLet<Kind = HdlLetKind> {
pub(crate) attrs: Vec<Attribute>,
pub(crate) hdl_attr: HdlAttr<Nothing>,
pub(crate) hdl_attr: HdlAttr<Nothing, kw::hdl>,
pub(crate) let_token: Token![let],
pub(crate) mut_token: Option<Token![mut]>,
pub(crate) name: Ident,
@ -1112,7 +1112,7 @@ impl<T: ToString> ToTokens for ImplicitName<T> {
}
struct Visitor<'a> {
module_kind: ModuleKind,
module_kind: Option<ModuleKind>,
errors: Errors,
io: Vec<ModuleIO>,
block_depth: usize,
@ -1120,22 +1120,33 @@ struct Visitor<'a> {
}
impl Visitor<'_> {
fn take_hdl_attr<T: Parse>(&mut self, attrs: &mut Vec<Attribute>) -> Option<HdlAttr<T>> {
fn take_hdl_attr<T: Parse>(
&mut self,
attrs: &mut Vec<Attribute>,
) -> Option<HdlAttr<T, kw::hdl>> {
self.errors.unwrap_or(
HdlAttr::parse_and_take_attr(attrs),
Some(syn::parse2::<T>(quote! {}).unwrap().into()),
)
}
fn require_normal_module(&mut self, spanned: impl ToTokens) {
fn require_normal_module_or_fn(&mut self, spanned: impl ToTokens) {
match self.module_kind {
ModuleKind::Extern => {
Some(ModuleKind::Extern) => {
self.errors
.error(spanned, "not allowed in #[hdl_module(extern)]");
}
ModuleKind::Normal => {}
Some(ModuleKind::Normal) | None => {}
}
}
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing>, expr_if: ExprIf) -> Expr {
fn require_module(&mut self, spanned: impl ToTokens) {
match self.module_kind {
None => {
self.errors.error(spanned, "not allowed in #[hdl] fn");
}
Some(_) => {}
}
}
fn process_hdl_if(&mut self, hdl_attr: HdlAttr<Nothing, kw::hdl>, expr_if: ExprIf) -> Expr {
let ExprIf {
attrs,
if_token,
@ -1143,7 +1154,7 @@ impl Visitor<'_> {
then_branch,
else_branch,
} = expr_if;
self.require_normal_module(if_token);
self.require_normal_module_or_fn(if_token);
let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr {
Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if),
expr => expr,
@ -1208,11 +1219,12 @@ impl Visitor<'_> {
.to_tokens(expr);
});
let mut attrs = hdl_let.attrs.clone();
self.require_module(kind);
match self.module_kind {
ModuleKind::Extern => attrs.push(parse_quote_spanned! {hdl_let.let_token.span=>
Some(ModuleKind::Extern) => attrs.push(parse_quote_spanned! {hdl_let.let_token.span=>
#[allow(unused_variables)]
}),
ModuleKind::Normal => {}
Some(ModuleKind::Normal) | None => {}
}
let let_stmt = Local {
attrs,
@ -1249,7 +1261,7 @@ impl Visitor<'_> {
},
semi_token,
} = hdl_let;
self.require_normal_module(instance);
self.require_normal_module_or_fn(instance);
let mut expr = instance.to_token_stream();
paren.surround(&mut expr, |expr| {
let name_str = ImplicitName {
@ -1276,7 +1288,7 @@ impl Visitor<'_> {
fn process_hdl_let_reg_builder(&mut self, hdl_let: HdlLet<HdlLetKindRegBuilder>) -> Local {
let name = &hdl_let.name;
let reg_builder = hdl_let.kind.reg_builder;
self.require_normal_module(reg_builder);
self.require_normal_module_or_fn(reg_builder);
let mut expr = reg_builder.to_token_stream();
hdl_let.kind.reg_builder_paren.surround(&mut expr, |expr| {
let name_str = ImplicitName {
@ -1327,7 +1339,7 @@ impl Visitor<'_> {
fn process_hdl_let_wire(&mut self, hdl_let: HdlLet<HdlLetKindWire>) -> Local {
let name = &hdl_let.name;
let wire = hdl_let.kind.wire;
self.require_normal_module(wire);
self.require_normal_module_or_fn(wire);
let ty_expr = unwrap_or_static_type(hdl_let.kind.ty_expr.as_ref(), wire.span());
let mut expr = wire.to_token_stream();
hdl_let.kind.paren.surround(&mut expr, |expr| {
@ -1361,7 +1373,7 @@ impl Visitor<'_> {
let name = &hdl_let.name;
let memory_fn = hdl_let.kind.memory_fn;
let memory_fn_name = memory_fn.name();
self.require_normal_module(memory_fn_name);
self.require_normal_module_or_fn(memory_fn_name);
let mut expr = memory_fn_name.to_token_stream();
let (paren, arg) = match memory_fn {
MemoryFn::Memory {
@ -1543,7 +1555,7 @@ impl Fold for Visitor<'_> {
}
fn fold_attribute(&mut self, attr: Attribute) -> Attribute {
if is_hdl_attr(&attr) {
if is_hdl_attr::<kw::hdl>(&attr) {
self.errors
.error(&attr, "#[hdl] attribute not supported here");
}
@ -1610,8 +1622,9 @@ impl Fold for Visitor<'_> {
fn fold_local(&mut self, let_stmt: Local) -> Local {
match self
.errors
.ok(HdlAttr::<Nothing>::parse_and_leave_attr(&let_stmt.attrs))
{
.ok(HdlAttr::<Nothing, kw::hdl>::parse_and_leave_attr(
&let_stmt.attrs,
)) {
None => return empty_let(),
Some(None) => return fold_local(self, let_stmt),
Some(Some(HdlAttr { .. })) => {}
@ -1646,7 +1659,7 @@ impl Fold for Visitor<'_> {
}
pub(crate) fn transform_body(
module_kind: ModuleKind,
module_kind: Option<ModuleKind>,
mut body: Box<Block>,
parsed_generics: &ParsedGenerics,
) -> syn::Result<(Box<Block>, Vec<ModuleIO>)> {

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{module::transform_body::Visitor, HdlAttr};
use crate::{kw, module::transform_body::Visitor, HdlAttr};
use quote::{format_ident, quote_spanned};
use syn::{
parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath,
@ -10,10 +10,10 @@ use syn::{
impl Visitor<'_> {
pub(crate) fn process_hdl_array(
&mut self,
hdl_attr: HdlAttr<Nothing>,
hdl_attr: HdlAttr<Nothing, kw::hdl>,
mut expr_array: ExprArray,
) -> Expr {
self.require_normal_module(hdl_attr);
self.require_normal_module_or_fn(hdl_attr);
for elem in &mut expr_array.elems {
*elem = parse_quote_spanned! {elem.span()=>
::fayalite::expr::ToExpr::to_expr(&(#elem))
@ -23,10 +23,10 @@ impl Visitor<'_> {
}
pub(crate) fn process_hdl_repeat(
&mut self,
hdl_attr: HdlAttr<Nothing>,
hdl_attr: HdlAttr<Nothing, kw::hdl>,
mut expr_repeat: ExprRepeat,
) -> Expr {
self.require_normal_module(hdl_attr);
self.require_normal_module_or_fn(hdl_attr);
let repeated_value = &expr_repeat.expr;
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
@ -35,10 +35,10 @@ impl Visitor<'_> {
}
pub(crate) fn process_hdl_struct(
&mut self,
hdl_attr: HdlAttr<Nothing>,
hdl_attr: HdlAttr<Nothing, kw::hdl>,
expr_struct: ExprStruct,
) -> Expr {
self.require_normal_module(&hdl_attr);
self.require_normal_module_or_fn(&hdl_attr);
let name_span = expr_struct.path.segments.last().unwrap().ident.span();
let builder_ident = format_ident!("__builder", span = name_span);
let empty_builder = if expr_struct.qself.is_some()
@ -91,10 +91,10 @@ impl Visitor<'_> {
}
pub(crate) fn process_hdl_tuple(
&mut self,
hdl_attr: HdlAttr<Nothing>,
hdl_attr: HdlAttr<Nothing, kw::hdl>,
expr_tuple: ExprTuple,
) -> Expr {
self.require_normal_module(hdl_attr);
self.require_normal_module_or_fn(hdl_attr);
parse_quote_spanned! {expr_tuple.span()=>
::fayalite::expr::ToExpr::to_expr(&#expr_tuple)
}

View file

@ -2,6 +2,7 @@
// See Notices.txt for copyright information
use crate::{
fold::{impl_fold, DoFold},
kw,
module::transform_body::{with_debug_clone_and_fold, Visitor},
Errors, HdlAttr, PairsIterExt,
};
@ -749,7 +750,7 @@ struct HdlMatchParseState<'a> {
impl Visitor<'_> {
pub(crate) fn process_hdl_match(
&mut self,
_hdl_attr: HdlAttr<Nothing>,
_hdl_attr: HdlAttr<Nothing, kw::hdl>,
expr_match: ExprMatch,
) -> Expr {
let span = expr_match.match_token.span();
@ -761,7 +762,7 @@ impl Visitor<'_> {
brace_token: _,
arms,
} = expr_match;
self.require_normal_module(match_token);
self.require_normal_module_or_fn(match_token);
let mut state = HdlMatchParseState {
match_span: span,
errors: &mut self.errors,