pub use cairo_lang_macro_attributes::*;
pub use cairo_lang_quote::*;
#[doc(hidden)]
pub use linkme;
use std::cell::RefCell;
use cairo_lang_macro_stable::ffi::StableSlice;
use cairo_lang_macro_stable::{
StableExpansionsList, StablePostProcessContext, StableProcMacroResult, StableTextSpan,
};
use std::ffi::{CStr, CString, c_char};
use std::num::NonZeroU8;
use std::ops::Deref;
mod types;
pub use types::*;
#[no_mangle]
pub static CAIRO_LANG_MACRO_API_VERSION: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(2) };
thread_local!(static CONTEXT: RefCell<AllocationContext> = RefCell::default() );
thread_local!(static CALL_SITE: RefCell<(u32, u32)> = RefCell::default());
#[doc(hidden)]
#[derive(Clone)]
pub struct ExpansionDefinition {
pub name: &'static str,
pub doc: &'static str,
pub kind: ExpansionKind,
pub fun: ExpansionFunc,
}
#[derive(Clone)]
pub enum ExpansionFunc {
Attr(fn(TokenStream, TokenStream) -> ProcMacroResult),
Other(fn(TokenStream) -> ProcMacroResult),
}
#[doc(hidden)]
#[linkme::distributed_slice]
pub static MACRO_DEFINITIONS_SLICE: [ExpansionDefinition];
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn list_expansions_v2() -> StableExpansionsList {
let list = MACRO_DEFINITIONS_SLICE
.iter()
.map(|m| m.clone().into_stable())
.collect();
StableSlice::new(list)
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn free_expansions_list_v2(list: StableExpansionsList) {
let v = list.into_owned();
v.into_iter().for_each(|v| {
ExpansionDefinition::free_owned(v);
});
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn expand_v2(
item_name: *const c_char,
call_site: StableTextSpan,
stable_attr: cairo_lang_macro_stable::StableTokenStream,
stable_token_stream: cairo_lang_macro_stable::StableTokenStream,
) -> cairo_lang_macro_stable::StableResultWrapper {
CONTEXT.with(|ctx_cell| {
let size_hint: usize = stable_token_stream.size_hint + stable_attr.size_hint;
ctx_cell.replace(AllocationContext::with_capacity(size_hint));
let ctx_borrow = ctx_cell.borrow();
let ctx: &AllocationContext = ctx_borrow.deref();
CALL_SITE.replace((call_site.start, call_site.end));
let token_stream = TokenStream::from_stable_in(&stable_token_stream, ctx);
let attr_token_stream = TokenStream::from_stable_in(&stable_attr, ctx);
let item_name = CStr::from_ptr(item_name)
.to_str()
.expect("item name must be a valid string");
let fun = MACRO_DEFINITIONS_SLICE
.iter()
.find_map(|m| {
if m.name == item_name {
Some(m.fun.clone())
} else {
None
}
})
.expect("procedural macro not found");
let result = match fun {
ExpansionFunc::Attr(fun) => fun(attr_token_stream, token_stream),
ExpansionFunc::Other(fun) => fun(token_stream),
};
let result: StableProcMacroResult = result.into_stable();
cairo_lang_macro_stable::StableResultWrapper {
input: stable_token_stream,
input_attr: stable_attr,
output: result,
}
})
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn free_result_v2(result: StableProcMacroResult) {
ProcMacroResult::free_owned_stable(result);
}
#[doc(hidden)]
#[linkme::distributed_slice]
pub static CALLBACKS: [Callback];
#[doc(hidden)]
#[derive(Clone)]
#[non_exhaustive]
pub enum Callback {
PostProcess(fn(PostProcessContext)),
Fingerprint(fn() -> u64),
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn post_process_callback_v2(
context: StablePostProcessContext,
) -> StablePostProcessContext {
if !CALLBACKS.is_empty() {
let context = PostProcessContext::from_stable(&context);
for callback in CALLBACKS {
if let Callback::PostProcess(fun) = callback {
fun(context.clone());
}
}
}
context
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn doc_v2(item_name: *mut c_char) -> *mut c_char {
let item_name = CStr::from_ptr(item_name).to_string_lossy().to_string();
let doc = MACRO_DEFINITIONS_SLICE
.iter()
.find_map(|m| {
if m.name == item_name.as_str() {
Some(m.doc)
} else {
None
}
})
.expect("procedural macro not found");
CString::new(doc).unwrap().into_raw()
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn free_doc_v2(doc: *mut c_char) {
if !doc.is_null() {
let _ = CString::from_raw(doc);
}
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn fingerprint_v2() -> u64 {
let mut result: u64 = 0;
for callback in CALLBACKS {
if let Callback::Fingerprint(fun) = callback {
result ^= fun() + 0x9e3779b9 + (result << 6) + (result >> 2)
}
}
result
}
#[doc(hidden)]
pub fn no_op_attr(_attr: TokenStream, input: TokenStream) -> ProcMacroResult {
ProcMacroResult::new(input)
}