1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#![warn(missing_docs, clippy::all, clippy::pedantic)]
#![deny(rustdoc::broken_intra_doc_links, missing_debug_implementations)]
#![allow(clippy::module_name_repetitions)]
#![feature(proc_macro_diagnostic)]

//! Derive macro for the docbot crate

mod attrs;
mod bits;
mod docs;
mod inputs;
mod opts;
mod trie;

use bits::{help::HelpParts, id::IdParts, parse::ParseParts, path::PathParts};
use proc_macro::TokenStream as TokenStream1;
use proc_macro2::{Span, TokenStream};
use quote::quote_spanned;
use syn::{parse_macro_input, spanned::Spanned, DeriveInput};

pub(crate) type Error = (anyhow::Error, Span);
pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;

/// Construct a new command or set of commands from doc comments
#[proc_macro_derive(Docbot, attributes(docbot))]
pub fn derive_docbot(input: TokenStream1) -> TokenStream1 {
    let input = parse_macro_input!(input);

    match derive_docbot_impl(&input) {
        Ok(s) => s.into(),
        Err((e, s)) => {
            s.unwrap()
                .error(format!("Macro execution failed:\n{:?}", e))
                .emit();
            TokenStream1::new()
        },
    }
}

fn derive_docbot_impl(input: &DeriveInput) -> Result<TokenStream> {
    let inputs = inputs::assemble(input)?;
    let id_parts = bits::id::emit(&inputs);
    let path_parts = bits::path::emit(&inputs, &id_parts);
    let parse_parts = bits::parse::emit(&inputs, &id_parts, &path_parts);
    let help_parts = bits::help::emit(&inputs);

    // Quote variables
    let IdParts {
        items: id_items, ..
    } = id_parts;
    let PathParts {
        items: path_items, ..
    } = path_parts;
    let ParseParts { items: parse_items } = parse_parts;
    let HelpParts { items: help_items } = help_parts;

    let toks = quote_spanned! { input.span() =>
        #id_items
        #path_items
        #parse_items
        #help_items
    };

    // eprintln!("{}", toks);

    Ok(toks)
}