1pub use cairo_lang_macro_attributes::*;
19pub use cairo_lang_quote::*;
20
21#[doc(hidden)]
22pub use linkme;
23
24use std::cell::RefCell;
25
26use cairo_lang_macro_stable::ffi::StableSlice;
27use cairo_lang_macro_stable::{
28 StableExpansionsList, StablePostProcessContext, StableProcMacroResult, StableTextSpan,
29};
30use std::ffi::{CStr, CString, c_char};
31use std::num::NonZeroU8;
32use std::ops::Deref;
33
34mod types;
35pub use types::*;
36
37#[no_mangle]
38pub static CAIRO_LANG_MACRO_API_VERSION: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(2) };
39
40thread_local!(static CONTEXT: RefCell<AllocationContext> = RefCell::default() );
42
43thread_local!(static CALL_SITE: RefCell<(u32, u32)> = RefCell::default());
44
45#[doc(hidden)]
46#[derive(Clone)]
47pub struct ExpansionDefinition {
48 pub name: &'static str,
49 pub doc: &'static str,
50 pub kind: ExpansionKind,
51 pub fun: ExpansionFunc,
52}
53
54#[derive(Clone)]
55pub enum ExpansionFunc {
56 Attr(fn(TokenStream, TokenStream) -> ProcMacroResult),
57 Other(fn(TokenStream) -> ProcMacroResult),
58}
59
60#[doc(hidden)]
64#[linkme::distributed_slice]
65pub static MACRO_DEFINITIONS_SLICE: [ExpansionDefinition];
66
67#[doc(hidden)]
74#[no_mangle]
75pub unsafe extern "C" fn list_expansions_v2() -> StableExpansionsList {
76 let list = MACRO_DEFINITIONS_SLICE
77 .iter()
78 .map(|m| m.clone().into_stable())
79 .collect();
80 StableSlice::new(list)
81}
82
83#[doc(hidden)]
90#[no_mangle]
91pub unsafe extern "C" fn free_expansions_list_v2(list: StableExpansionsList) {
92 let v = list.into_owned();
93 v.into_iter().for_each(|v| {
94 ExpansionDefinition::free_owned(v);
95 });
96}
97
98#[doc(hidden)]
107#[no_mangle]
108pub unsafe extern "C" fn expand_v2(
109 item_name: *const c_char,
110 call_site: StableTextSpan,
111 stable_attr: cairo_lang_macro_stable::StableTokenStream,
112 stable_token_stream: cairo_lang_macro_stable::StableTokenStream,
113) -> cairo_lang_macro_stable::StableResultWrapper {
114 CONTEXT.with(|ctx_cell| {
115 let size_hint: usize = stable_token_stream.size_hint + stable_attr.size_hint;
118 ctx_cell.replace(AllocationContext::with_capacity(size_hint));
121 let ctx_borrow = ctx_cell.borrow();
122 let ctx: &AllocationContext = ctx_borrow.deref();
123 CALL_SITE.replace((call_site.start, call_site.end));
125 let token_stream = TokenStream::from_stable_in(&stable_token_stream, ctx);
127 let attr_token_stream = TokenStream::from_stable_in(&stable_attr, ctx);
128 let item_name = CStr::from_ptr(item_name)
129 .to_str()
130 .expect("item name must be a valid string");
131 let fun = MACRO_DEFINITIONS_SLICE
132 .iter()
133 .find_map(|m| {
134 if m.name == item_name {
135 Some(m.fun.clone())
136 } else {
137 None
138 }
139 })
140 .expect("procedural macro not found");
141 let result = match fun {
142 ExpansionFunc::Attr(fun) => fun(attr_token_stream, token_stream),
143 ExpansionFunc::Other(fun) => fun(token_stream),
144 };
145 let result: StableProcMacroResult = result.into_stable();
146 cairo_lang_macro_stable::StableResultWrapper {
147 input: stable_token_stream,
148 input_attr: stable_attr,
149 output: result,
150 }
151 })
152}
153
154#[doc(hidden)]
164#[no_mangle]
165pub unsafe extern "C" fn free_result_v2(result: StableProcMacroResult) {
166 ProcMacroResult::free_owned_stable(result);
167}
168
169#[doc(hidden)]
171#[linkme::distributed_slice]
172pub static CALLBACKS: [Callback];
173
174#[doc(hidden)]
175#[derive(Clone)]
176#[non_exhaustive]
177pub enum Callback {
178 PostProcess(fn(PostProcessContext)),
179 Fingerprint(fn() -> u64),
180}
181
182#[doc(hidden)]
192#[no_mangle]
193pub unsafe extern "C" fn post_process_callback_v2(
194 context: StablePostProcessContext,
195) -> StablePostProcessContext {
196 if !CALLBACKS.is_empty() {
197 let context = PostProcessContext::from_stable(&context);
199 for callback in CALLBACKS {
200 if let Callback::PostProcess(fun) = callback {
201 fun(context.clone());
202 }
203 }
204 }
205 context
206}
207
208#[doc(hidden)]
213#[no_mangle]
214pub unsafe extern "C" fn doc_v2(item_name: *mut c_char) -> *mut c_char {
215 let item_name = CStr::from_ptr(item_name).to_string_lossy().to_string();
216 let doc = MACRO_DEFINITIONS_SLICE
217 .iter()
218 .find_map(|m| {
219 if m.name == item_name.as_str() {
220 Some(m.doc)
221 } else {
222 None
223 }
224 })
225 .expect("procedural macro not found");
226 CString::new(doc).unwrap().into_raw()
227}
228
229#[doc(hidden)]
234#[no_mangle]
235pub unsafe extern "C" fn free_doc_v2(doc: *mut c_char) {
236 if !doc.is_null() {
237 let _ = CString::from_raw(doc);
238 }
239}
240
241#[doc(hidden)]
256#[no_mangle]
257pub unsafe extern "C" fn fingerprint_v2() -> u64 {
258 let mut result: u64 = 0;
259 for callback in CALLBACKS {
260 if let Callback::Fingerprint(fun) = callback {
261 result ^= fun() + 0x9e3779b9 + (result << 6) + (result >> 2)
263 }
264 }
265 result
266}
267
268#[doc(hidden)]
273pub fn no_op_attr(_attr: TokenStream, input: TokenStream) -> ProcMacroResult {
274 ProcMacroResult::new(input)
275}