#[allow(dead_code)]
mod ast;
#[allow(dead_code)]
mod codegen;
#[allow(dead_code)]
mod parser;
use proc_macro::TokenStream;
use proc_macro2::Ident;
use proc_macro_crate::{crate_name, FoundCrate};
use quote::quote;
#[proc_macro]
pub fn xml(input: TokenStream) -> TokenStream {
let input = proc_macro2::TokenStream::from(input);
match parser::parse_template(input).and_then(|template| {
let runtime_path = xdoc_runtime_path().map_err(parser::ParseError::from_message)?;
codegen::generate_template(&template, runtime_path).map_err(|error| {
parser::ParseError::from_message(format!("code generation failed: {}", error.message()))
})
}) {
Ok(tokens) => tokens.into(),
Err(error) => compile_error(error.message()).into(),
}
}
fn xdoc_runtime_path() -> Result<proc_macro2::TokenStream, String> {
match crate_name("xdoc-rs").map_err(|error| error.to_string())? {
FoundCrate::Itself => Ok(quote! { ::xdoc }),
FoundCrate::Name(name) => {
if name == "xdoc_rs" {
return Ok(quote! { ::xdoc });
}
let ident = Ident::new(&name, proc_macro2::Span::call_site());
Ok(quote! { ::#ident })
}
}
}
fn compile_error(message: &str) -> proc_macro2::TokenStream {
let message = proc_macro2::Literal::string(message);
quote! {
compile_error!(#message)
}
}