1#![cfg_attr(test, recursion_limit = "512")]
4use proc_macro2::{Span, TokenStream};
5use quote::{quote, ToTokens};
6use std::io::{ErrorKind, Write};
7use syn::{
8 bracketed, parenthesized,
9 parse::{Parse, ParseStream, Parser},
10 parse_quote,
11 punctuated::Pair,
12 spanned::Spanned,
13 AttrStyle, Attribute, Error, Item, ItemFn, Token,
14};
15
16mod fold;
17mod hdl_bundle;
18mod hdl_enum;
19mod hdl_type_common;
20mod module;
21
22pub(crate) trait CustomToken:
23 Copy
24 + Spanned
25 + ToTokens
26 + std::fmt::Debug
27 + Eq
28 + std::hash::Hash
29 + Default
30 + quote::IdentFragment
31 + Parse
32{
33 const IDENT_STR: &'static str;
34}
35
36mod kw {
37 pub(crate) use syn::token::Extern as extern_;
38
39 macro_rules! custom_keyword {
40 ($kw:ident) => {
41 syn::custom_keyword!($kw);
42
43 impl quote::IdentFragment for $kw {
44 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
45 f.write_str(stringify!($kw))
46 }
47
48 fn span(&self) -> Option<proc_macro2::Span> {
49 Some(self.span)
50 }
51 }
52
53 crate::fold::no_op_fold!($kw);
54
55 impl crate::CustomToken for $kw {
56 const IDENT_STR: &'static str = stringify!($kw);
57 }
58 };
59 }
60
61 custom_keyword!(clock_domain);
62 custom_keyword!(connect_inexact);
63 custom_keyword!(custom_bounds);
64 custom_keyword!(flip);
65 custom_keyword!(hdl);
66 custom_keyword!(hdl_module);
67 custom_keyword!(input);
68 custom_keyword!(incomplete_wire);
69 custom_keyword!(instance);
70 custom_keyword!(m);
71 custom_keyword!(memory);
72 custom_keyword!(memory_array);
73 custom_keyword!(memory_with_init);
74 custom_keyword!(no_reset);
75 custom_keyword!(no_runtime_generics);
76 custom_keyword!(no_static);
77 custom_keyword!(outline_generated);
78 custom_keyword!(output);
79 custom_keyword!(reg_builder);
80 custom_keyword!(reset);
81 custom_keyword!(skip);
82 custom_keyword!(target);
83 custom_keyword!(wire);
84}
85
86type Pound = Token![#]; #[derive(Clone, Debug)]
89pub(crate) struct HdlAttr<T, KW> {
90 pub(crate) pound_token: Pound,
91 pub(crate) style: AttrStyle,
92 pub(crate) bracket_token: syn::token::Bracket,
93 pub(crate) kw: KW,
94 pub(crate) paren_token: Option<syn::token::Paren>,
95 pub(crate) body: T,
96}
97
98crate::fold::impl_fold! {
99 struct HdlAttr<T, KW,> {
100 pound_token: Pound,
101 style: AttrStyle,
102 bracket_token: syn::token::Bracket,
103 kw: KW,
104 paren_token: Option<syn::token::Paren>,
105 body: T,
106 }
107}
108
109#[allow(dead_code)]
110impl<T, KW> HdlAttr<T, KW> {
111 pub(crate) fn split_body(self) -> (HdlAttr<(), KW>, T) {
112 let Self {
113 pound_token,
114 style,
115 bracket_token,
116 kw,
117 paren_token,
118 body,
119 } = self;
120 (
121 HdlAttr {
122 pound_token,
123 style,
124 bracket_token,
125 kw,
126 paren_token,
127 body: (),
128 },
129 body,
130 )
131 }
132 pub(crate) fn replace_body<T2>(self, body: T2) -> HdlAttr<T2, KW> {
133 let Self {
134 pound_token,
135 style,
136 bracket_token,
137 kw,
138 paren_token,
139 body: _,
140 } = self;
141 HdlAttr {
142 pound_token,
143 style,
144 bracket_token,
145 kw,
146 paren_token,
147 body,
148 }
149 }
150 pub(crate) fn as_ref(&self) -> HdlAttr<&T, KW>
151 where
152 KW: Clone,
153 {
154 let Self {
155 pound_token,
156 style,
157 bracket_token,
158 ref kw,
159 paren_token,
160 ref body,
161 } = *self;
162 HdlAttr {
163 pound_token,
164 style,
165 bracket_token,
166 kw: kw.clone(),
167 paren_token,
168 body,
169 }
170 }
171 pub(crate) fn try_map<R, E, F: FnOnce(T) -> Result<R, E>>(
172 self,
173 f: F,
174 ) -> Result<HdlAttr<R, KW>, E> {
175 let Self {
176 pound_token,
177 style,
178 bracket_token,
179 kw,
180 paren_token,
181 body,
182 } = self;
183 Ok(HdlAttr {
184 pound_token,
185 style,
186 bracket_token,
187 kw,
188 paren_token,
189 body: f(body)?,
190 })
191 }
192 pub(crate) fn map<R, F: FnOnce(T) -> R>(self, f: F) -> HdlAttr<R, KW> {
193 let Self {
194 pound_token,
195 style,
196 bracket_token,
197 kw,
198 paren_token,
199 body,
200 } = self;
201 HdlAttr {
202 pound_token,
203 style,
204 bracket_token,
205 kw,
206 paren_token,
207 body: f(body),
208 }
209 }
210 fn to_attr(&self) -> Attribute
211 where
212 T: ToTokens,
213 KW: ToTokens,
214 {
215 parse_quote! { #self }
216 }
217}
218
219impl<T: Default, KW: Default> Default for HdlAttr<T, KW> {
220 fn default() -> Self {
221 T::default().into()
222 }
223}
224
225impl<T, KW: Default> From<T> for HdlAttr<T, KW> {
226 fn from(body: T) -> Self {
227 HdlAttr {
228 pound_token: Default::default(),
229 style: AttrStyle::Outer,
230 bracket_token: Default::default(),
231 kw: Default::default(),
232 paren_token: Default::default(),
233 body,
234 }
235 }
236}
237
238impl<T: ToTokens, KW: ToTokens + Spanned> ToTokens for HdlAttr<T, KW> {
239 fn to_tokens(&self, tokens: &mut TokenStream) {
240 self.pound_token.to_tokens(tokens);
241 match self.style {
242 AttrStyle::Inner(style) => style.to_tokens(tokens),
243 AttrStyle::Outer => {}
244 };
245 self.bracket_token.surround(tokens, |tokens| {
246 self.kw.to_tokens(tokens);
247 match self.paren_token {
248 Some(paren_token) => {
249 paren_token.surround(tokens, |tokens| self.body.to_tokens(tokens))
250 }
251 None => {
252 let body = self.body.to_token_stream();
253 if !body.is_empty() {
254 syn::token::Paren(self.kw.span())
255 .surround(tokens, |tokens| tokens.extend([body]));
256 }
257 }
258 }
259 });
260 }
261}
262
263fn is_hdl_attr<KW: CustomToken>(attr: &Attribute) -> bool {
264 attr.path().is_ident(KW::IDENT_STR)
265}
266
267impl<T: Parse, KW: Parse> HdlAttr<T, KW> {
268 fn parse_and_take_attr(attrs: &mut Vec<Attribute>) -> syn::Result<Option<Self>>
269 where
270 KW: ToTokens,
271 {
272 let mut retval = None;
273 let mut errors = Errors::new();
274 attrs.retain(|attr| {
275 if let Ok(kw) = syn::parse2::<KW>(attr.path().to_token_stream()) {
276 if retval.is_some() {
277 errors.push(Error::new_spanned(
278 attr,
279 format_args!("more than one #[{}] attribute", kw.to_token_stream()),
280 ));
281 }
282 errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v)));
283 false
284 } else {
285 true
286 }
287 });
288 errors.finish()?;
289 Ok(retval)
290 }
291 fn parse_and_leave_attr(attrs: &[Attribute]) -> syn::Result<Option<Self>>
292 where
293 KW: ToTokens,
294 {
295 let mut retval = None;
296 let mut errors = Errors::new();
297 for attr in attrs {
298 if let Ok(kw) = syn::parse2::<KW>(attr.path().to_token_stream()) {
299 if retval.is_some() {
300 errors.push(Error::new_spanned(
301 attr,
302 format_args!("more than one #[{}] attribute", kw.to_token_stream()),
303 ));
304 }
305 errors.unwrap_or_default(Self::parse_attr(attr).map(|v| retval = Some(v)));
306 }
307 }
308 errors.finish()?;
309 Ok(retval)
310 }
311 fn parse_attr(attr: &Attribute) -> syn::Result<Self> {
312 match attr.style {
313 AttrStyle::Outer => Parser::parse2(Self::parse_outer, attr.to_token_stream()),
314 AttrStyle::Inner(_) => Parser::parse2(Self::parse_inner, attr.to_token_stream()),
315 }
316 }
317 fn parse_starting_with_brackets(
318 pound_token: Token![#],
319 style: AttrStyle,
320 input: ParseStream,
321 ) -> syn::Result<Self> {
322 let bracket_content;
323 let bracket_token = bracketed!(bracket_content in input);
324 let kw = bracket_content.parse()?;
325 let paren_content;
326 let body;
327 let paren_token;
328 if bracket_content.is_empty() {
329 body = match syn::parse2(TokenStream::default()) {
330 Ok(body) => body,
331 Err(_) => {
332 parenthesized!(paren_content in bracket_content);
333 unreachable!();
334 }
335 };
336 paren_token = None;
337 } else {
338 paren_token = Some(parenthesized!(paren_content in bracket_content));
339 body = paren_content.parse()?;
340 }
341 Ok(Self {
342 pound_token,
343 style,
344 bracket_token,
345 kw,
346 paren_token,
347 body,
348 })
349 }
350 fn parse_inner(input: ParseStream) -> syn::Result<Self> {
351 let pound_token = input.parse()?;
352 let style = AttrStyle::Inner(input.parse()?);
353 Self::parse_starting_with_brackets(pound_token, style, input)
354 }
355 fn parse_outer(input: ParseStream) -> syn::Result<Self> {
356 let pound_token = input.parse()?;
357 let style = AttrStyle::Outer;
358 Self::parse_starting_with_brackets(pound_token, style, input)
359 }
360}
361
362#[allow(dead_code)]
363pub(crate) trait PairsIterExt: Sized + Iterator {
364 fn map_pair<T1, T2, P1, P2, ValueFn: FnMut(T1) -> T2, PunctFn: FnMut(P1) -> P2>(
365 self,
366 mut value_fn: ValueFn,
367 mut punct_fn: PunctFn,
368 ) -> impl Iterator<Item = Pair<T2, P2>>
369 where
370 Self: Iterator<Item = Pair<T1, P1>>,
371 {
372 self.map(move |p| {
373 let (t, p) = p.into_tuple();
374 let t = value_fn(t);
375 let p = p.map(&mut punct_fn);
376 Pair::new(t, p)
377 })
378 }
379 fn filter_map_pair<T1, T2, P1, P2, ValueFn: FnMut(T1) -> Option<T2>, PunctFn: FnMut(P1) -> P2>(
380 self,
381 mut value_fn: ValueFn,
382 mut punct_fn: PunctFn,
383 ) -> impl Iterator<Item = Pair<T2, P2>>
384 where
385 Self: Iterator<Item = Pair<T1, P1>>,
386 {
387 self.filter_map(move |p| {
388 let (t, p) = p.into_tuple();
389 let t = value_fn(t)?;
390 let p = p.map(&mut punct_fn);
391 Some(Pair::new(t, p))
392 })
393 }
394 fn map_pair_value<T1, T2, P, F: FnMut(T1) -> T2>(
395 self,
396 f: F,
397 ) -> impl Iterator<Item = Pair<T2, P>>
398 where
399 Self: Iterator<Item = Pair<T1, P>>,
400 {
401 self.map_pair(f, |v| v)
402 }
403 fn filter_map_pair_value<T1, T2, P, F: FnMut(T1) -> Option<T2>>(
404 self,
405 f: F,
406 ) -> impl Iterator<Item = Pair<T2, P>>
407 where
408 Self: Iterator<Item = Pair<T1, P>>,
409 {
410 self.filter_map_pair(f, |v| v)
411 }
412 fn map_pair_value_mut<'a, T1: 'a, T2: 'a, P: Clone + 'a, F: FnMut(T1) -> T2 + 'a>(
413 self,
414 f: F,
415 ) -> impl Iterator<Item = Pair<T2, P>> + 'a
416 where
417 Self: Iterator<Item = Pair<T1, &'a mut P>> + 'a,
418 {
419 self.map_pair(f, |v| v.clone())
420 }
421 fn filter_map_pair_value_mut<
422 'a,
423 T1: 'a,
424 T2: 'a,
425 P: Clone + 'a,
426 F: FnMut(T1) -> Option<T2> + 'a,
427 >(
428 self,
429 f: F,
430 ) -> impl Iterator<Item = Pair<T2, P>> + 'a
431 where
432 Self: Iterator<Item = Pair<T1, &'a mut P>> + 'a,
433 {
434 self.filter_map_pair(f, |v| v.clone())
435 }
436 fn map_pair_value_ref<'a, T1: 'a, T2: 'a, P: Clone + 'a, F: FnMut(T1) -> T2 + 'a>(
437 self,
438 f: F,
439 ) -> impl Iterator<Item = Pair<T2, P>> + 'a
440 where
441 Self: Iterator<Item = Pair<T1, &'a P>> + 'a,
442 {
443 self.map_pair(f, |v| v.clone())
444 }
445 fn filter_map_pair_value_ref<
446 'a,
447 T1: 'a,
448 T2: 'a,
449 P: Clone + 'a,
450 F: FnMut(T1) -> Option<T2> + 'a,
451 >(
452 self,
453 f: F,
454 ) -> impl Iterator<Item = Pair<T2, P>> + 'a
455 where
456 Self: Iterator<Item = Pair<T1, &'a P>> + 'a,
457 {
458 self.filter_map_pair(f, |v| v.clone())
459 }
460}
461
462impl<T, P, Iter: Iterator<Item = Pair<T, P>>> PairsIterExt for Iter {}
463
464pub(crate) struct Errors {
465 error: Option<Error>,
466 finished: bool,
467}
468
469impl Drop for Errors {
470 fn drop(&mut self) {
471 if !std::thread::panicking() {
472 assert!(self.finished, "didn't run finish");
473 }
474 }
475}
476
477impl Errors {
478 pub(crate) fn new() -> Self {
479 Self {
480 error: None,
481 finished: false,
482 }
483 }
484 pub(crate) fn push(&mut self, e: Error) -> &mut Self {
485 match self.error {
486 Some(ref mut old) => old.combine(e),
487 None => self.error = Some(e),
488 }
489 self
490 }
491 pub(crate) fn push_result(&mut self, e: syn::Result<()>) -> &mut Self {
492 self.ok(e);
493 self
494 }
495 pub(crate) fn error(
496 &mut self,
497 tokens: impl ToTokens,
498 message: impl std::fmt::Display,
499 ) -> &mut Self {
500 self.push(Error::new_spanned(tokens, message));
501 self
502 }
503 pub(crate) fn ok<T>(&mut self, v: syn::Result<T>) -> Option<T> {
504 match v {
505 Ok(v) => Some(v),
506 Err(e) => {
507 self.push(e);
508 None
509 }
510 }
511 }
512 pub(crate) fn unwrap_or_else<T>(
513 &mut self,
514 v: syn::Result<T>,
515 fallback: impl FnOnce() -> T,
516 ) -> T {
517 match v {
518 Ok(v) => v,
519 Err(e) => {
520 self.push(e);
521 fallback()
522 }
523 }
524 }
525 pub(crate) fn unwrap_or<T>(&mut self, v: syn::Result<T>, fallback: T) -> T {
526 self.unwrap_or_else(v, || fallback)
527 }
528 pub(crate) fn unwrap_or_default<T: Default>(&mut self, v: syn::Result<T>) -> T {
529 self.unwrap_or_else(v, T::default)
530 }
531 pub(crate) fn finish(&mut self) -> syn::Result<()> {
532 self.finished = true;
533 match self.error.take() {
534 Some(e) => Err(e),
535 None => Ok(()),
536 }
537 }
538}
539
540impl Default for Errors {
541 fn default() -> Self {
542 Self::new()
543 }
544}
545
546macro_rules! impl_extra_traits_for_options {
547 (
548 #[no_ident_fragment]
549 $enum_vis:vis enum $option_enum_name:ident {
550 $($Variant:ident($key:ident),)*
551 }
552 ) => {
553 impl Copy for $option_enum_name {}
554 };
555 (
556 $enum_vis:vis enum $option_enum_name:ident {
557 $($Variant:ident($key:ident),)*
558 }
559 ) => {
560 impl Copy for $option_enum_name {}
561
562 impl PartialEq for $option_enum_name {
563 fn eq(&self, other: &Self) -> bool {
564 self.cmp(other).is_eq()
565 }
566 }
567
568 impl Eq for $option_enum_name {}
569
570 impl PartialOrd for $option_enum_name {
571 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
572 Some(self.cmp(other))
573 }
574 }
575
576 impl Ord for $option_enum_name {
577 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
578 self.variant().cmp(&other.variant())
579 }
580 }
581
582 impl quote::IdentFragment for $option_enum_name {
583 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
584 let _ = f;
585 match *self {
586 $(Self::$Variant(ref v) => quote::IdentFragment::fmt(&v.0, f),)*
587 }
588 }
589
590 fn span(&self) -> Option<proc_macro2::Span> {
591 match *self {
592 $(Self::$Variant(ref v) => quote::IdentFragment::span(&v.0),)*
593 }
594 }
595 }
596
597 impl $option_enum_name {
598 #[allow(dead_code)]
599 $enum_vis fn span(&self) -> proc_macro2::Span {
600 quote::IdentFragment::span(self).unwrap()
601 }
602 }
603 };
604 (
605 $(#[no_ident_fragment])?
606 $enum_vis:vis enum $option_enum_name:ident {
607 $($Variant:ident($key:ident $(, $value:ty)?),)*
608 }
609 ) => {};
610}
611
612pub(crate) use impl_extra_traits_for_options;
613
614macro_rules! options {
615 (
616 #[options = $options_name:ident]
617 $($tt:tt)*
618 ) => {
619 crate::options! {
620 #[options = $options_name, punct = syn::Token![,], allow_duplicates = false]
621 $($tt)*
622 }
623 };
624 (
625 #[options = $options_name:ident, punct = $Punct:ty, allow_duplicates = true]
626 $(#[$($enum_meta:tt)*])*
627 $enum_vis:vis enum $option_enum_name:ident {
628 $($Variant:ident($key:ident $(, $value:ty)?),)*
629 }
630 ) => {
631 crate::options! {
632 #[options = $options_name, punct = $Punct, allow_duplicates = (true)]
633 $(#[$($enum_meta)*])*
634 $enum_vis enum $option_enum_name {
635 $($Variant($key $(, $value)?),)*
636 }
637 }
638
639 impl Extend<$option_enum_name> for $options_name {
640 fn extend<T: IntoIterator<Item = $option_enum_name>>(&mut self, iter: T) {
641 iter.into_iter().for_each(|v| match v {
642 $($option_enum_name::$Variant(v) => {
643 self.$key = Some(v);
644 })*
645 });
646 }
647 }
648
649 impl FromIterator<$option_enum_name> for $options_name {
650 fn from_iter<T: IntoIterator<Item = $option_enum_name>>(iter: T) -> Self {
651 let mut retval = Self::default();
652 retval.extend(iter);
653 retval
654 }
655 }
656
657 impl Extend<$options_name> for $options_name {
658 fn extend<T: IntoIterator<Item = $options_name>>(&mut self, iter: T) {
659 iter.into_iter().for_each(|v| {
660 $(if let Some(v) = v.$key {
661 self.$key = Some(v);
662 })*
663 });
664 }
665 }
666
667 impl FromIterator<$options_name> for $options_name {
668 fn from_iter<T: IntoIterator<Item = $options_name>>(iter: T) -> Self {
669 let mut retval = Self::default();
670 retval.extend(iter);
671 retval
672 }
673 }
674 };
675 (
676 #[options = $options_name:ident, punct = $Punct:ty, allow_duplicates = $allow_duplicates:expr]
677 $(#[$($enum_meta:tt)*])*
678 $enum_vis:vis enum $option_enum_name:ident {
679 $($Variant:ident($key:ident $(, $value:ty)?),)*
680 }
681 ) => {
682 crate::options! {
683 $(#[$($enum_meta)*])*
684 $enum_vis enum $option_enum_name {
685 $($Variant($key $(, $value)?),)*
686 }
687 }
688
689 #[derive(Clone, Debug, Default)]
690 #[allow(non_snake_case)]
691 $enum_vis struct $options_name {
692 $(
693 $enum_vis $key: Option<(crate::kw::$key, $(syn::token::Paren, $value)?)>,
694 )*
695 }
696
697 crate::fold::impl_fold! {
698 struct $options_name<> {
699 $($key: Option<(crate::kw::$key, $(syn::token::Paren, $value)?)>,)*
700 }
701 }
702
703 const _: () = {
704 #[derive(Clone, Debug)]
705 $enum_vis struct Iter($enum_vis $options_name);
706
707 impl IntoIterator for $options_name {
708 type Item = $option_enum_name;
709 type IntoIter = Iter;
710
711 fn into_iter(self) -> Self::IntoIter {
712 Iter(self)
713 }
714 }
715
716 impl Iterator for Iter {
717 type Item = $option_enum_name;
718
719 fn next(&mut self) -> Option<Self::Item> {
720 $(
721 if let Some(value) = self.0.$key.take() {
722 return Some($option_enum_name::$Variant(value));
723 }
724 )*
725 None
726 }
727
728 #[allow(unused_mut, unused_variables)]
729 fn fold<B, F: FnMut(B, Self::Item) -> B>(mut self, mut init: B, mut f: F) -> B {
730 $(
731 if let Some(value) = self.0.$key.take() {
732 init = f(init, $option_enum_name::$Variant(value));
733 }
734 )*
735 init
736 }
737 }
738 };
739
740 impl syn::parse::Parse for $options_name {
741 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
742 #![allow(unused_mut, unused_variables, unreachable_code)]
743 let mut retval = Self::default();
744 while !input.is_empty() {
745 let old_input = input.fork();
746 match input.parse::<$option_enum_name>()? {
747 $($option_enum_name::$Variant(v) => {
748 if retval.$key.replace(v).is_some() && !$allow_duplicates {
749 return Err(old_input.error(concat!("duplicate ", stringify!($key), " option")));
750 }
751 })*
752 }
753 if input.is_empty() {
754 break;
755 }
756 input.parse::<$Punct>()?;
757 }
758 Ok(retval)
759 }
760 }
761
762 impl quote::ToTokens for $options_name {
763 #[allow(unused_mut, unused_variables, unused_assignments)]
764 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
765 let mut separator: Option<$Punct> = None;
766 $(if let Some(v) = &self.$key {
767 separator.to_tokens(tokens);
768 separator = Some(Default::default());
769 v.0.to_tokens(tokens);
770 $(v.1.surround(
771 tokens,
772 |tokens| <$value as quote::ToTokens>::to_tokens(&v.2, tokens),
773 );)?
774 })*
775 }
776 }
777 };
778 (
779 $(#[$($enum_meta:tt)*])*
780 $enum_vis:vis enum $option_enum_name:ident {
781 $($Variant:ident($key:ident $(, $value:ty)?),)*
782 }
783 ) => {
784 #[derive(Clone, Debug)]
785 $enum_vis enum $option_enum_name {
786 $($Variant((crate::kw::$key, $(syn::token::Paren, $value)?)),)*
787 }
788
789 crate::impl_extra_traits_for_options! {
790 $(#[$($enum_meta)*])*
791 $enum_vis enum $option_enum_name {
792 $($Variant($key $(, $value)?),)*
793 }
794 }
795
796 crate::fold::impl_fold! {
797 enum $option_enum_name<> {
798 $($Variant((crate::kw::$key, $(syn::token::Paren, $value)?)),)*
799 }
800 }
801
802 impl syn::parse::Parse for $option_enum_name {
803 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
804 let lookahead = input.lookahead1();
805 $(
806 if lookahead.peek(crate::kw::$key) {
807 #[allow(unused_variables)]
808 let paren_content: syn::parse::ParseBuffer;
809 return Ok($option_enum_name::$Variant((
810 input.parse()?,
811 $(
812 syn::parenthesized!(paren_content in input),
813 paren_content.parse::<$value>()?,
814 )?
815 )));
816 }
817 )*
818 Err(lookahead.error())
819 }
820 }
821
822 impl quote::ToTokens for $option_enum_name {
823 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
824 let _ = tokens;
825 match *self {
826 $($option_enum_name::$Variant(ref v) => {
827 v.0.to_tokens(tokens);
828 $(
829 let value: &$value = &v.2;
830 v.1.surround(tokens, |tokens| value.to_tokens(tokens));
831 )?
832 })*
833 }
834 }
835 }
836
837 impl $option_enum_name {
838 #[allow(dead_code)]
839 fn variant(&self) -> usize {
840 #[repr(usize)]
841 enum Variant {
842 $($Variant,)*
843 __Last, }
845 match *self {
846 $(Self::$Variant(..) => Variant::$Variant as usize,)*
847 }
848 }
849 }
850 };
851}
852
853pub(crate) use options;
854
855pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStream {
856 let out_dir = env!("OUT_DIR");
857 let mut file = tempfile::Builder::new()
858 .prefix(prefix)
859 .rand_bytes(6)
860 .suffix(".tmp.rs")
861 .tempfile_in(out_dir)
862 .unwrap();
863 struct PrintOnPanic<'a>(&'a TokenStream);
864 impl Drop for PrintOnPanic<'_> {
865 fn drop(&mut self) {
866 if std::thread::panicking() {
867 println!("{}", self.0);
868 }
869 }
870 }
871 let _print_on_panic = PrintOnPanic(&contents);
872 let contents = prettyplease::unparse(&parse_quote! { #contents });
873 let hash = <sha2::Sha256 as sha2::Digest>::digest(&contents);
874 let hash = base16ct::HexDisplay(&hash[..5]);
875 file.write_all(contents.as_bytes()).unwrap();
876 let dest_file = std::path::Path::new(out_dir).join(format!("{prefix}{hash:x}.rs"));
877 match file.persist_noclobber(&dest_file) {
879 Err(e) if e.error.kind() == ErrorKind::AlreadyExists => {}
880 e => {
881 e.unwrap();
882 }
883 }
884 eprintln!("generated {}", dest_file.display());
885 let dest_file = dest_file.to_str().unwrap();
886
887 quote! {
888 include!(#dest_file);
889 }
890}
891
892fn hdl_module_impl(item: ItemFn) -> syn::Result<TokenStream> {
893 let func = module::ModuleFn::parse_from_fn(item)?;
894 let options = func.config_options();
895 let mut contents = func.generate();
896 if options.outline_generated.is_some() {
897 contents = outline_generated(contents, "module-");
898 }
899 Ok(contents)
900}
901
902pub fn hdl_module(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
903 let kw = kw::hdl_module::default();
904 hdl_module_impl(syn::parse2(quote! { #[#kw(#attr)] #item })?)
905}
906
907pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
908 let kw = kw::hdl::default();
909 let item = syn::parse2::<Item>(quote! { #[#kw(#attr)] #item })?;
910 match item {
911 Item::Enum(item) => hdl_enum::hdl_enum(item),
912 Item::Struct(item) => hdl_bundle::hdl_bundle(item),
913 Item::Fn(item) => hdl_module_impl(item),
914 _ => Err(syn::Error::new(
915 Span::call_site(),
916 "top-level #[hdl] can only be used on structs, enums, or functions",
917 )),
918 }
919}