asteracea_proc_macro_definitions/
lib.rs

1#![forbid(unsafe_code)]
2#![allow(clippy::unneeded_field_pattern)]
3
4extern crate proc_macro;
5
6mod component_declaration;
7mod map_message;
8mod parse_with_context;
9mod part;
10mod try_parse;
11mod yank_any;
12
13use self::{
14	component_declaration::ComponentDeclaration,
15	map_message::MapMessage,
16	part::{GenerateContext, Part},
17	try_parse::TryParse,
18	yank_any::YankAny,
19};
20use lazy_static::lazy_static;
21use proc_macro::TokenStream as TokenStream1;
22use proc_macro2::{Span, TokenStream as TokenStream2};
23use proc_macro_crate::crate_name;
24use quote::{quote, ToTokens};
25use syn::{
26	parse::{Parse, ParseStream},
27	parse_macro_input, Ident, Result,
28};
29
30use syn::Error;
31
32#[proc_macro]
33pub fn component(input: TokenStream1) -> TokenStream1 {
34	let component_declaration = parse_macro_input!(input as ComponentDeclaration);
35	let tokens: TokenStream2 = component_declaration
36		.into_tokens()
37		.unwrap_or_else(|error| error.to_compile_error());
38	tokens.into()
39}
40
41struct BumpFormat {
42	asteracea: Ident,
43	bump_span: Span,
44	input: TokenStream2,
45}
46
47#[proc_macro]
48pub fn bump_format(input: TokenStream1) -> TokenStream1 {
49	let bump_format = parse_macro_input!(input as BumpFormat);
50	quote!(#bump_format).into()
51}
52
53impl Parse for BumpFormat {
54	fn parse(input: ParseStream) -> Result<Self> {
55		//TODO: This is pretty hacky.
56		// Change it to a better location once that feature is stable in proc_macro2.
57		let bump_span = input.cursor().span();
58		let asteracea = asteracea_ident(bump_span);
59		Ok(BumpFormat {
60			asteracea,
61			bump_span,
62			input: input.parse()?,
63		})
64	}
65}
66
67impl ToTokens for BumpFormat {
68	fn to_tokens(&self, output: &mut TokenStream2) {
69		let BumpFormat {
70			asteracea,
71			bump_span,
72			input,
73		} = self;
74		let bump = Ident::new("bump", *bump_span);
75		output.extend(quote! {
76			#asteracea::lignin_schema::lignin::Node::Text(
77				#asteracea::lignin_schema::lignin::bumpalo::format!(in #bump, #input)
78					.into_bump_str()
79			)
80		});
81	}
82}
83
84enum FragmentConfiguration {}
85impl Configuration for FragmentConfiguration {
86	const NAME: &'static str = "fragment!";
87	const CAN_CAPTURE: bool = false;
88}
89
90#[proc_macro]
91pub fn fragment(input: TokenStream1) -> TokenStream1 {
92	parse_macro_input!(input as Part<FragmentConfiguration>)
93		.part_tokens(&GenerateContext::default())
94		.unwrap_or_else(|error| error.to_compile_error())
95		.into()
96}
97
98// TODO: Accept reexported asteracea module made available via `use`.
99lazy_static! {
100	static ref ASTERACEA_NAME: String =
101		crate_name("asteracea").unwrap_or_else(|_| "asteracea".to_owned());
102}
103fn asteracea_ident(span: Span) -> Ident {
104	Ident::new(&*ASTERACEA_NAME, span)
105}
106
107/// SEE: <https://github.com/rust-lang/rust/issues/34537#issuecomment-554590043>
108mod workaround_module {
109	pub trait Configuration {
110		const NAME: &'static str;
111		const CAN_CAPTURE: bool;
112	}
113}
114use workaround_module::Configuration;
115
116fn warn(location: Span, message: &str) -> Result<()> {
117	Err(Error::new(location, message.to_string()))
118}