goto1717/
lib.rs

1//mod goto;
2//pub use crate::goto::{label, goto};
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, parse::{Parse, ParseStream, Result}, parse_quote, ItemFn, LitStr, Stmt, Meta, MetaList, MetaNameValue, punctuated::Punctuated, Attribute,
6token::Comma, Expr, Lit, Token, PatIdent, Pat, Local, PathSegment, DeriveInput};
7use proc_macro2::{TokenStream as TokenStream2, Span};
8use Mademoiselle_Entropia::custom_traits::STRN;
9mod lex;
10struct AttrArgs {
11    metas: Punctuated<Meta, Token![,]>,
12}
13impl Default for AttrArgs {
14    fn default() -> Self {
15        Self {
16            metas: Punctuated::new(),
17        }
18    }
19}
20struct AttrArgsIter<'a> {
21    iter: syn::punctuated::Iter<'a, Meta>, // Use a slice iterator for the Punctuated collection
22}
23
24impl<'a> Iterator for AttrArgsIter<'a> {
25    type Item = &'a Meta; // Yield references to Meta items
26
27    fn next(&mut self) -> Option<Self::Item> {
28        self.iter.next() // Call the next method on the slice iterator
29    }
30}
31
32// Implement a method to return the iterator
33impl AttrArgs {
34    fn iter(&self) -> AttrArgsIter {
35        AttrArgsIter {
36            iter: self.metas.iter(), // Create an iterator from the Punctuated collection
37        }
38    }
39}
40impl Parse for AttrArgs {
41    fn parse(input: ParseStream) -> syn::Result<Self> {
42        let metas = Punctuated::<Meta, Token![,]>::parse_terminated_with(input, Meta::parse)?;
43        Ok(AttrArgs { metas })
44    }
45}
46   macro_rules! _prnt_func {
47    ($name:ident, $body:block) => {
48        pub fn $name() {
49            println!("{}", stringify!($body));
50        }
51    };
52}
53#[proc_macro_attribute]
54pub fn inject(_attr: TokenStream, item: TokenStream) -> TokenStream {
55    let mut input: ItemFn = parse_macro_input!(item as ItemFn);
56    let mut new_stmts = Vec::<Stmt>::new(); 
57    let strn_stmts = format! ("{:?}", input.block.stmts);
58    let add_to: Stmt = syn::parse_quote! {
59                println!("yst {}", #strn_stmts);
60            };
61    let stmts = &input.block.stmts;
62    let stmts_len = stmts.len();
63    for j in 0..stmts_len {
64        if j == stmts_len -1 {new_stmts.push ( add_to.clone() ); }
65        new_stmts.push(stmts [j].clone());
66    }            
67    input.block.stmts = new_stmts;
68    return TokenStream::from(quote! { #input })
69}
70#[proc_macro_attribute]
71pub fn inject_after_hello(_attr: TokenStream, item: TokenStream) -> TokenStream {
72    let mut input: ItemFn = parse_macro_input!(item as ItemFn);
73    let mut new_stmts = Vec::<Stmt>::new(); 
74
75    for stmt in input.block.stmts {
76        // Push the original statement
77        new_stmts.push(stmt.clone());
78
79        // Check if it's the specific println! macro invocation
80        if let Stmt::Expr(syn::Expr::Macro(expr_macro), _) = &stmt {
81            let macro_path = &expr_macro.mac.path.segments;
82            let macro_tokens = expr_macro.mac.tokens.to_string();
83            if macro_path.len() == 1
84                && macro_path[0].ident == "println"
85                && macro_tokens.contains("\"hello\"")
86            {
87                // Inject code after the matched println!
88                new_stmts.push(syn::parse_quote! {
89                    println!("-- injected after Hello, world!");
90                });
91            }
92        }
93    }
94
95    input.block.stmts = new_stmts;
96
97    TokenStream::from(quote! { #input })
98}
99//#![feature(trace_macros)]
100//trace_macros!(true);
101#[proc_macro_attribute]
102pub fn inject_tst(args: TokenStream, item: TokenStream) -> TokenStream {
103   let (sub_fn, sub_fn_id) = prnt_func ("sub_fn", item.clone());
104    let item_str = format! ("{}", item.clone() );
105    let mut ext_quote = quote!();
106    let item0 = item.clone();
107    let mut input: ItemFn = parse_macro_input!(item0 as ItemFn);
108    let lit: LitStr = LitStr::new("Alice", proc_macro2::Span::call_site());
109    let val = Expr::Lit(syn::ExprLit {
110        attrs: vec![],
111        lit: Lit::Str(lit),
112    });
113    let meta_name_value = MetaNameValue {
114        path: syn::parse_quote!(name), // The name of the attribute
115        eq_token: Default::default(),   // The '=' token
116        value: val,
117    };
118   /* let mut args_meta: Meta = Meta::NameValue(meta_name_value);
119    let mut stop_err = false;
120    match syn::parse::<Meta>(args) {
121        Ok(meta) => { args_meta = meta; },
122        Err(e) => { let err = format! ("customized compiler's error {:#?}", e); stop_err = true;
123                    return TokenStream::from (quote! {
124                        pub fn lets_prnt_func () {
125                            println! ("{}", #err);
126                        }
127                    })},
128    };*/
129    let args = parse_macro_input! (args as AttrArgs);
130    //if stop_err {compile_error! ("stop_err"); }
131    for arg in args.iter() {
132        match arg {
133            Meta::Path(path) => { ext_quote.extend (
134                quote! { println!("Simple attribute: {:?}", #path); }
135                );
136            }
137            Meta::List(list) => { 
138                let list = list.tokens.clone();
139            ext_quote.extend (
140                quote! {println!("Attribute with args: {:?}", #list); }
141                );
142            }
143            Meta::NameValue(name_value) => { 
144                let ident = name_value.path.get_ident().unwrap().to_string();
145                let value = name_value.value.clone();
146            ext_quote.extend (
147            quote! { println!("Name-value attribute: {} = {:?}", 
148                    #ident,
149                    #value);
150                } );
151            }
152        };
153    }
154    //let attrss = &attr_in.attrs;
155 //   println!("tssst {} val {}", _attrs.to_string(), "42");
156  /*for attr in attrss {
157    println!("enter to attrs", );
158    if !attr.path().is_ident("tst00") {
159        match &attr.meta {
160            Meta::Path(_) => {
161                // Just #[my_attr]
162            }
163            Meta::List(list) => {
164                // #[my_attr(arg1, arg2)]
165                let nested = list.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated);
166                
167                match nested {
168                    Ok(nested) => {
169                        for meta in nested {
170                            match meta {
171                                Meta::Path(path) => println!("Path: {:?}", path),
172                                Meta::List(list) => println!("Nested list: {:?}", list),
173                                Meta::NameValue(nv) => {
174                                    println!("Name-value: {} = {:#?}", 
175                                        nv.path.get_ident().unwrap(), 
176                                        nv.value
177                                    );
178                                }
179                            }
180                        }
181                    }
182                    Err(e) => {
183                        // Handle parse error
184                        return TokenStream::from(e.to_compile_error());
185                    }
186                }
187            }
188            Meta::NameValue(nv) => {
189                // #[my_attr = value]
190                println!("Attribute value: {:?}", nv.value);
191            }
192        }
193    }
194}*/
195
196    let input_str = format! ("{:#?}", input);
197    let mut new_stmts = Vec::<Stmt>::new(); 
198    let strn_stmts = format! ("{:?}", input.block.stmts);
199    let add_to: Stmt = syn::parse_quote! {
200                println!("yst {}\n{}\n{}", #strn_stmts, #input_str, #item_str);
201            };
202    let stmts = &input.block.stmts;
203    let stmts_len = stmts.len();
204    for j in 0..stmts_len {
205        if j == stmts_len -1 {new_stmts.push ( add_to.clone() ); }
206        new_stmts.push(stmts [j].clone());
207    }            
208    input.block.stmts = new_stmts; 
209    let input_str = format! ("{:#?}", input);
210    let ext_quote_str = ext_quote.to_string();
211    //let sub_fn: Stmt = parse_quote! (sub_fn as Stmt);
212    return TokenStream::from(quote! {
213        #sub_fn
214        pub fn lets_prnt_func () {
215            println! ("input {} ext {}", #input_str, #ext_quote_str );
216            #ext_quote
217            #sub_fn_id();
218            }} )
219}
220#[proc_macro]
221pub fn my_macro(input: TokenStream) -> TokenStream {
222    // Create a new identifier with a specific span
223    let ident = syn::Ident::new("my_variable", Span::call_site());
224    let mut new_stmts = Vec::<Stmt>::new(); 
225    let mut input: ItemFn = parse_macro_input!(input as ItemFn);
226    // Generate code that uses the identifier
227    let expanded = TokenStream::from (quote! {
228        let #ident = #input;
229    } );
230
231    expanded.into()
232}
233  #[proc_macro]
234   pub fn stmt_to_tokenstream(input: TokenStream) -> TokenStream {
235       // Parse the input TokenStream into a Stmt
236       let stmt: Stmt = parse_macro_input!(input as Stmt);
237
238       // Convert the Stmt back to a TokenStream
239       let output = quote! {
240           #stmt
241       };
242
243       output.into()
244   }
245   #[proc_macro_attribute]
246   pub fn just_prnt (args: TokenStream, input: TokenStream) -> TokenStream {
247        let func_body = input.to_string();
248        let out = quote! {
249            pub fn lets_prnt_func () {
250                println! ("{}", #func_body);
251            }
252        };
253        return out.into()
254   }
255   #[inline]
256   fn prnt_func (name_fn: &str, input: TokenStream) -> (TokenStream2, syn::Ident) {
257        let func_body = input.to_string();
258        let name_fn_str = name_fn.strn();
259        let name_fn = strn_to_Ident (&name_fn);
260        // let fn_name = parse_macro_input!( name_fn as LitStr ).value();
261    
262    // Convert the string to an Ident
263    //let name_fn = syn::Ident::new(&name_fn, proc_macro2::Span::call_site());
264        let out = quote! {
265            pub fn #name_fn () {
266            //println!("++++++++++++++++++++++++++++++");
267                println! ("{}", #func_body);
268            }
269        };
270       // let out: ItemFn = parse_quote!( out as ItemFn );
271       let sub_fn: proc_macro2::TokenStream = out.into();
272       let sub_fn_id = syn::Ident::new( &name_fn_str, proc_macro2::Span::call_site());
273        return (sub_fn, sub_fn_id)
274   }
275fn strn_to_LitStr(s: &str) -> LitStr {
276    LitStr::new(s, Span::call_site())
277}
278fn strn_to_Ident(s: &str) -> syn::Ident {
279    syn::Ident::new(s, Span::call_site())
280}
281#[proc_macro_attribute]
282pub fn prnt_vars(_attr: TokenStream, item: TokenStream) -> TokenStream {
283use syn::spanned::Spanned;
284    let item_fn = item.clone();
285    let mut input_fn = parse_macro_input!( item_fn as ItemFn);
286     let span = input_fn.attrs.first().map(|attr| attr.span()).unwrap_or_else(proc_macro2::Span::call_site);
287    let fn_name = &input_fn.sig.ident;
288    let mut new_stmts = Vec::new();
289
290    for stmt in input_fn.block.stmts {
291        if let Stmt::Local(local) = &stmt {
292           // let line_num = local.pat.span().start().line;
293            //let mut var_names = Vec::new();
294            
295            // Recursively collect all identifiers from the pattern
296            //collect_idents(&local.pat, &mut var_names);
297            let span = local.init.as_ref().unwrap().expr.clone(); // works
298          //  let span = local.pat.attrs.clone();
299            let local_pat = format! ("{:?}\nspanЪЪ {:?}", &local, span );
300            
301            //if !var_names.is_empty() {
302                let print_stmts = /*var_names.iter().map(|ident| { */
303                    quote! {
304                       /* println!("[VAR] {} = {:?} (declared at line {})", 
305                            stringify!(#ident), #ident, #line_num); */
306                        println! ("Loc {:?}", #local_pat);
307                    };
308            //}
309                
310                new_stmts.push(quote! {
311                    #stmt
312                    #print_stmts
313                });
314                //continue;
315            }
316        new_stmts.push(quote! { #stmt });
317        }
318
319    let expanded = quote! {
320        fn #fn_name() {
321            println!("[FN] Entering {}", stringify!(#fn_name));
322            #(#new_stmts)*
323        }
324    };
325
326    expanded.into()
327}
328
329// Helper function to recursively collect identifiers from patterns
330/* fn collect_idents(pat: &Pat, idents: &mut Vec<syn::Ident>) {
331    match pat {
332        Pat::Ident(pat_ident) => {
333            idents.push(pat_ident.ident.clone());
334        }
335        Pat::Tuple(tuple) => {
336            for elem in &tuple.elems {
337                collect_idents(elem, idents);
338            }
339        }
340        Pat::Struct(struct_pat) => {
341            for field in &struct_pat.fields {
342                collect_idents(&field.pat, idents);
343            }
344        }
345        Pat::TupleStruct(tuple_struct) => {
346            for elem in tuple_struct.path.segments.iter() {
347                collect_idents(elem, idents);
348            }
349        }
350        Pat::Slice(slice) => {
351            for elem in &slice.elems {
352                collect_idents(elem, idents);
353            }
354        }
355          Pat::Box(box_pat) => {
356            collect_idents(&box_pat.pat, idents);
357        }
358        Pat::Ref(ref_pat) => {
359            collect_idents(&ref_pat.pat, idents);
360        }
361        Pat::Range(range) => {
362            if let Some(start) = &range.start {
363                collect_idents(start, idents);
364            }
365            if let Some(end) = &range.end {
366                collect_idents(end, idents);
367            }
368        }
369        Pat::Wild(_) => {}
370        _ => {} // Ignore other pattern types
371    }
372} */
373//pub use crate::inject_after_hello; 
374// https://www.freecodecamp.org/news/procedural-macros-in-rust/