1use proc_macro2::{Span, TokenStream};
7use quote::{quote, ToTokens};
8use syn::{
9 parse::{Parse, ParseStream},
10 parse_macro_input, Block, LitInt, Result,
11};
12use syn::{parse2, Ident};
13
14extern crate proc_macro;
15
16struct SimpleCodeLoop {
17 loops: usize,
18 block: Block,
19}
20impl Parse for SimpleCodeLoop {
21 fn parse(input: ParseStream) -> Result<Self> {
22 let loops: LitInt = input.parse()?;
23 let block: Block = input.parse()?;
24
25 let loops: usize = loops.base10_parse()?;
26
27 Ok(Self { loops, block })
28 }
29}
30
31struct AdvancedCodeLoop {
32 index_variable: Ident,
33 loops: usize,
34 number_type: Ident,
35 block: Block,
36}
37impl Parse for AdvancedCodeLoop {
38 fn parse(input: ParseStream) -> Result<Self> {
39 let index_variable: Ident = input.parse()?;
40 let number_type: Ident = input
41 .parse()
42 .unwrap_or_else(|_| Ident::new("usize", Span::call_site()));
43 let loops: LitInt = input.parse()?;
44 let block: Block = input.parse()?;
45
46 let loops: usize = loops.base10_parse()?;
47
48 Ok(Self {
49 index_variable,
50 loops,
51 number_type,
52 block,
53 })
54 }
55}
56
57#[proc_macro]
85pub fn repeat(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
86 let input = TokenStream::from(input);
87 if let Ok(code_loop) = parse2::<AdvancedCodeLoop>(input.clone()) {
88 let mut code = TokenStream::new();
89 for i in 0..code_loop.loops {
90 let block = &code_loop.block;
91 let variable = &code_loop.index_variable;
92 let kind = &code_loop.number_type;
93
94 let lit = LitInt::new(&i.to_string(), Span::call_site());
95
96 quote! {
97 {
98 const #variable: #kind = #lit;
99 #block
100 }
101 }
102 .to_tokens(&mut code);
103 }
104
105 code.into()
106 } else {
107 let input: proc_macro::TokenStream = input.into();
108 let code_loop = parse_macro_input!(input as SimpleCodeLoop);
109
110 let mut blocks = TokenStream::new();
111 for _ in 0..code_loop.loops {
112 code_loop.block.to_tokens(&mut blocks);
113 }
114
115 blocks.into()
116 }
117}