use proc_macro2::{Ident, Span, TokenStream}; use proc_macro_crate::{crate_name, FoundCrate}; use quote::quote; use syn::{parse::ParseStream, Error}; pub fn __make_absolute_path(name: &str, input: TokenStream) -> TokenStream { match name { // core and std are special because they don't appear in Cargo.toml "core" => quote! { ::core #input }, "std" => quote! { ::std #input }, name => { let prefix = match crate_name(name) { Ok(found) => match found { FoundCrate::Itself => quote! { crate }, FoundCrate::Name(name) => { let name = Ident::new(&name, Span::call_site()); quote! { :: #name } } }, Err(e) => { // proc_macro_crate failed to do its thing, so we try our best to // not break other people's builds. Assume we're being called // from another crate and the crate's author didn't rename us. eprintln!("uwui_dsl: proc_macro_crate failed to resolve crate {name}, expect macro bugs!"); eprintln!("uwui_dsl: proc_macro_crate has this to say: \"{e}\""); let name = Ident::new(name, Span::call_site()); quote! { :: #name } } }; quote! { #prefix #input } } } } macro_rules! absolute_path { ($crate_name:ident $(::$segment:ident)*) => { $crate::util::__make_absolute_path( stringify!($crate_name), ::quote::quote!($(::$segment)*) ) }; } pub(crate) use absolute_path; macro_rules! use_absolute { ($($crate_name:ident $(::$path:ident)* as $name:ident),* $(,)?) => { $( #[allow(non_snake_case)] let $name = $crate::util::absolute_path!($crate_name $(::$path)*); )* } } pub(crate) use use_absolute; const RESERVED_IDENT_PREFIX: &str = "__uwui_"; pub fn make_reserved(name: &str, span: impl Into>) -> Ident { let span = span.into().unwrap_or_else(Span::call_site); if name.starts_with(RESERVED_IDENT_PREFIX) { Ident::new(name, span) } else { Ident::new(&format!("{RESERVED_IDENT_PREFIX}{name}"), span) } } macro_rules! define_ident { ($($name:ident),* $(,)?) => { $( #[allow(non_snake_case)] let $name = $crate::util::make_reserved(stringify!($name), None); )* } } pub(crate) use define_ident; /// Recursively walk through a `ParseStream` and examine all identifiers. /// Emit an error for any identifiers that start with [`RESERVED_IDENT_PREFIX`] /// (`__uwui_`). /// /// TODO: See if we can wrap ParseStream in a monad that does this check when /// actually consuming the tokens pub fn scan_for_reserved_idents(stream: ParseStream) -> syn::Result { let fork = stream.fork(); match scan_buf_for_ident_prefix(&fork, RESERVED_IDENT_PREFIX) { Some(error) => Err(error), None => Ok(stream), } } fn scan_buf_for_ident_prefix(stream: ParseStream, prefix: &str) -> Option { todo!() }