docbot_derive/
lib.rs

1#![warn(missing_docs, clippy::all, clippy::pedantic, clippy::cargo)]
2#![deny(rustdoc::broken_intra_doc_links, missing_debug_implementations)]
3#![allow(clippy::module_name_repetitions)]
4#![feature(proc_macro_diagnostic)]
5
6//! Derive macro for the docbot crate
7
8mod attrs;
9mod bits;
10mod docs;
11mod inputs;
12mod opts;
13mod trie;
14
15use bits::{help::HelpParts, id::IdParts, parse::ParseParts, path::PathParts};
16use proc_macro::TokenStream;
17use proc_macro2::Span;
18use quote::quote_spanned;
19use syn::{parse_macro_input, spanned::Spanned, DeriveInput};
20
21pub(crate) type Error = (anyhow::Error, Span);
22pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;
23
24/// Construct a new command or set of commands from doc comments
25#[proc_macro_derive(Docbot, attributes(docbot))]
26pub fn derive_docbot(input: TokenStream) -> TokenStream {
27    let input: DeriveInput = parse_macro_input!(input);
28
29    let inputs = match inputs::assemble(&input) {
30        Ok(s) => s,
31        Err((e, s)) => {
32            s.unwrap()
33                .error(format!("Macro execution failed:\n{:?}", e))
34                .emit();
35            return TokenStream::new();
36        },
37    };
38
39    let id_parts = bits::id::emit(&inputs);
40    let path_parts = bits::path::emit(&inputs, &id_parts);
41    let parse_parts = bits::parse::emit(&inputs, &id_parts, &path_parts);
42    let help_parts = bits::help::emit(&inputs, &path_parts);
43
44    // Quote variables
45    let IdParts {
46        items: id_items, ..
47    } = id_parts;
48    let PathParts {
49        items: path_items, ..
50    } = path_parts;
51    let ParseParts { items: parse_items } = parse_parts;
52    let HelpParts { items: help_items } = help_parts;
53
54    let toks = quote_spanned! { input.span() =>
55        #id_items
56        #path_items
57        #parse_items
58        #help_items
59    };
60
61    // eprintln!("{}", toks);
62
63    toks.into()
64}