#![allow(clippy::needless_doctest_main)]
#![doc = include_str!("../snippets/docs.md")]
mod ast;
mod core;
mod error;
mod eval;
mod expand;
mod funcs;
mod interpreter;
mod parse;
mod resolve;
mod substitution;
mod util;
use crate::ast::{ComposeItemSpec, RawAST};
use crate::core::Environment;
use crate::interpreter::Interpreter;
use crate::util::unique_id::next_unique_id;
use proc_macro::TokenStream;
use quote::quote;
use std::rc::Rc;
use syn::parse_macro_input;
use util::deprecation::DeprecationService;
enum InvocationType {
Func(TokenStream),
Attr(TokenStream, TokenStream),
}
fn compose_core(prefix: &'static str, invocation: InvocationType) -> TokenStream {
let deprecation_service = DeprecationService::new_rc(prefix);
DeprecationService::maybe_set_global(deprecation_service);
let deprecation_service_scope = DeprecationService::scoped();
let environment = Rc::new(Environment::new_initialized(next_unique_id()));
Environment::maybe_set_global(environment.clone());
let interpreter = Interpreter::new(environment, deprecation_service_scope);
let args = match invocation {
InvocationType::Func(input) => parse_macro_input!(input as RawAST),
InvocationType::Attr(attr, item) => {
let spec: ComposeItemSpec = match syn::parse(attr) {
Ok(v) => v,
Err(err) => return TokenStream::from(err.into_compile_error()),
};
let item: proc_macro2::TokenStream = item.into();
let block_tokens: proc_macro2::TokenStream = quote!({ #item });
let block: syn::Block = match syn::parse2(block_tokens) {
Ok(v) => v,
Err(err) => return TokenStream::from(err.into_compile_error()),
};
RawAST::from_compose_item_spec(&spec, block)
}
};
match interpreter.execute(args) {
Ok(ts) => ts.into(),
Err(err) => {
let syn_err: syn::Error = err.into();
TokenStream::from(syn_err.into_compile_error())
}
}
}
#[doc = include_str!("../snippets/reference_h2.md")]
#[proc_macro_attribute]
pub fn compose_item(attr: TokenStream, item: TokenStream) -> TokenStream {
compose_core("compose_item!: ", InvocationType::Attr(attr, item))
}
#[doc = include_str!("../snippets/reference_h2.md")]
#[proc_macro]
pub fn compose(input: TokenStream) -> TokenStream {
compose_core("compose!: ", InvocationType::Func(input))
}
#[doc = include_str!("../snippets/reference_h2_compose_idents.md")]
#[deprecated(
since = "0.3.0",
note = "Renamed to compose!. Use compose!(...) instead."
)]
#[proc_macro]
pub fn compose_idents(input: TokenStream) -> TokenStream {
compose_core("compose_idents!: ", InvocationType::Func(input))
}