1#[allow(dead_code)]
8mod ast;
9#[allow(dead_code)]
10mod codegen;
11#[allow(dead_code)]
12mod parser;
13
14use proc_macro::TokenStream;
15use proc_macro2::Ident;
16use proc_macro_crate::{crate_name, FoundCrate};
17use quote::quote;
18
19#[proc_macro]
23pub fn xml(input: TokenStream) -> TokenStream {
24 let input = proc_macro2::TokenStream::from(input);
25
26 match parser::parse_template(input).and_then(|template| {
27 let runtime_path = xdoc_runtime_path().map_err(parser::ParseError::from_message)?;
28 codegen::generate_template(&template, runtime_path).map_err(|error| {
29 parser::ParseError::from_message(format!("code generation failed: {}", error.message()))
30 })
31 }) {
32 Ok(tokens) => tokens.into(),
33 Err(error) => compile_error(error.message()).into(),
34 }
35}
36
37fn xdoc_runtime_path() -> Result<proc_macro2::TokenStream, String> {
38 match crate_name("xdoc-rs").map_err(|error| error.to_string())? {
39 FoundCrate::Itself => Ok(quote! { ::xdoc }),
40 FoundCrate::Name(name) => {
41 if name == "xdoc_rs" {
42 return Ok(quote! { ::xdoc });
43 }
44 let ident = Ident::new(&name, proc_macro2::Span::call_site());
45 Ok(quote! { ::#ident })
46 }
47 }
48}
49
50fn compile_error(message: &str) -> proc_macro2::TokenStream {
51 let message = proc_macro2::Literal::string(message);
52 quote! {
53 compile_error!(#message)
54 }
55}