compose_idents/
lib.rs

1#![allow(clippy::needless_doctest_main)]
2#![doc = include_str!("../snippets/docs.md")]
3
4mod ast;
5mod core;
6mod deprecation;
7mod error;
8mod eval;
9mod funcs;
10mod interpreter;
11mod parse;
12mod resolve;
13mod unique_id;
14
15use crate::ast::ComposeIdentsArgs;
16use crate::deprecation::DeprecationService;
17use crate::interpreter::Interpreter;
18use proc_macro::TokenStream;
19use std::convert::TryInto;
20use syn::parse_macro_input;
21
22/// Compose identifiers from the provided parts and replace their aliases in the code block.
23///
24/// In addition to replacing identifier aliases it replaces tokens like `%alias%` in string
25/// literals (including in doc-attributes).
26///
27/// # Syntax
28///
29/// ```rust,ignore
30/// use compose_idents::compose_idents;
31///
32/// compose_idents!(
33///     // Alias is defined one or more arguments that are supposed to be concatenated
34///     alias1 = [part1, part2],
35///     // Multiple aliases could be defined
36///     // and they could be composed from arbitrary number of arguments
37///     // Which could be identifiers, strings, numbers, underscores or just arbitrary token
38///     // sequences
39///     alias2 = [part3, _, "part4", _, 1],
40///     // Functions could applied to the arguments, calls to functions could be nested
41///     alias3 = [some_func(part5), outer_func(inner_func(part6))],
42///     // ... more aliases
43///     {
44///         // Code block that uses aliases as identifiers
45///         // The aliases will be replaced with their replacements when the code is expanded
46///         let alias1 = 42;
47///
48///         fn alias2() -> u32 { 42 }
49///
50///         // Aliases could be also used for string-formatting using %alias% syntax
51///         #[doc = "Documentation for %alias3%"]
52///         fn alias3() -> u32 { 42 }
53///     },
54/// );
55/// ```
56///
57/// Semicolons could also be used as separators between the macro arguments for
58/// backwards-compatibility. Mixing separator styles in the same macro invocation is not allowed.
59///
60/// # Reference
61///
62#[doc = include_str!("../snippets/reference_h2.md")]
63#[proc_macro]
64pub fn compose_idents(input: TokenStream) -> TokenStream {
65    let deprecation_service = DeprecationService::scoped();
66    let args = parse_macro_input!(input as ComposeIdentsArgs);
67    let interpreter = Interpreter::new(args, deprecation_service);
68    match interpreter.execute() {
69        Ok(ts) => ts.into(),
70        Err(err) => {
71            let syn_err: syn::Error = err.try_into().unwrap_or_else(|_| {
72                syn::Error::new(proc_macro2::Span::call_site(), "Unknown error")
73            });
74            TokenStream::from(syn_err.into_compile_error())
75        }
76    }
77}