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 AUX_DATA_CALLBACKS: [fn(PostProcessContext)];
173
174#[doc(hidden)]
184#[no_mangle]
185pub unsafe extern "C" fn post_process_callback_v2(
186 context: StablePostProcessContext,
187) -> StablePostProcessContext {
188 if !AUX_DATA_CALLBACKS.is_empty() {
189 let context = PostProcessContext::from_stable(&context);
191 for fun in AUX_DATA_CALLBACKS {
192 fun(context.clone());
193 }
194 }
195 context
196}
197
198#[doc(hidden)]
203#[no_mangle]
204pub unsafe extern "C" fn doc_v2(item_name: *mut c_char) -> *mut c_char {
205 let item_name = CStr::from_ptr(item_name).to_string_lossy().to_string();
206 let doc = MACRO_DEFINITIONS_SLICE
207 .iter()
208 .find_map(|m| {
209 if m.name == item_name.as_str() {
210 Some(m.doc)
211 } else {
212 None
213 }
214 })
215 .expect("procedural macro not found");
216 CString::new(doc).unwrap().into_raw()
217}
218
219#[doc(hidden)]
224#[no_mangle]
225pub unsafe extern "C" fn free_doc_v2(doc: *mut c_char) {
226 if !doc.is_null() {
227 let _ = CString::from_raw(doc);
228 }
229}
230
231#[doc(hidden)]
236pub fn no_op_attr(_attr: TokenStream, input: TokenStream) -> ProcMacroResult {
237 ProcMacroResult::new(input)
238}