cairo_lang_proc_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::parse::Parser;
4use syn::punctuated::Punctuated;
5use syn::{ItemFn, Meta, Token, parse_macro_input};
6
7mod debug;
8mod heap_size;
9mod rewriter;
10
11#[proc_macro_derive(DebugWithDb, attributes(debug_db, hide_field_debug_with_db))]
12pub fn derive_debug_with_db(input: TokenStream) -> TokenStream {
13 debug::derive_debug_with_db(input)
14}
15
16#[proc_macro_derive(HeapSize)]
17pub fn derive_heap_size(input: TokenStream) -> TokenStream {
18 heap_size::derive_heap_size(input)
19}
20
21#[proc_macro_derive(SemanticObject, attributes(dont_rewrite))]
22pub fn derive_semantic_object(input: TokenStream) -> TokenStream {
23 rewriter::derive_semantic_object(input)
24}
25
26#[proc_macro_attribute]
42pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream {
43 let input_fn = parse_macro_input!(item as ItemFn);
44
45 let _fn_name = &input_fn.sig.ident;
46 let fn_vis = &input_fn.vis;
47 let fn_sig = &input_fn.sig;
48 let fn_block = &input_fn.block;
49 let fn_attrs = &input_fn.attrs;
50
51 let output = quote! {
53 #[::core::prelude::v1::test]
54 #(#fn_attrs)*
55 #fn_vis #fn_sig {
56 cairo_lang_test_utils::logging::init_logging(cairo_lang_test_utils::logging::level::ERROR);
58
59 #fn_block
61 }
62 };
63
64 TokenStream::from(output)
65}
66
67#[proc_macro_attribute]
68pub fn interned(attr: TokenStream, item: TokenStream) -> TokenStream {
69 let parser = Punctuated::<Meta, Token![,]>::parse_terminated;
70 #[allow(unused_mut)]
71 let mut args: Punctuated<Meta, Token![,]> =
72 if attr.is_empty() { Punctuated::new() } else { parser.parse(attr).unwrap() };
73
74 let has_heap_size = args
75 .iter()
76 .any(|meta| matches!(meta, Meta::NameValue(nv) if nv.path.is_ident("heap_size")));
77
78 if !has_heap_size {
79 let heap_size: Meta = syn::parse_quote!(heap_size = cairo_lang_utils::HeapSize::heap_size);
80 args.push(heap_size);
81 }
82
83 let salsa_attr = quote! { #[salsa::interned(#args)] };
84 let item: proc_macro2::TokenStream = item.into();
85 let output = quote! {
86 #salsa_attr
87 #item
88 };
89 output.into()
90}
91
92#[proc_macro_attribute]
93pub fn tracked(attr: TokenStream, item: TokenStream) -> TokenStream {
94 let parser = Punctuated::<Meta, Token![,]>::parse_terminated;
95 #[allow(unused_mut)]
96 let mut args: Punctuated<Meta, Token![,]> =
97 if attr.is_empty() { Punctuated::new() } else { parser.parse(attr).unwrap() };
98
99 let has_heap_size = args
100 .iter()
101 .any(|meta| matches!(meta, Meta::NameValue(nv) if nv.path.is_ident("heap_size")));
102
103 if !has_heap_size {
104 let heap_size: Meta = syn::parse_quote!(heap_size = cairo_lang_utils::HeapSize::heap_size);
105 args.push(heap_size);
106 }
107
108 let salsa_attr = quote! { #[salsa::tracked(#args)] };
109 let item: proc_macro2::TokenStream = item.into();
110 let output = quote! {
111 #salsa_attr
112 #item
113 };
114 output.into()
115}