mod attr;
mod cursor;
mod emit;
mod parse;
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
pub(crate) struct Error {
span: Span,
message: String,
}
impl Error {
pub(crate) fn new(span: Span, message: impl Into<String>) -> Self {
Error {
span,
message: message.into(),
}
}
fn into_compile_error(self) -> TokenStream {
let span = self.span;
let at = |mut tt: TokenTree| {
tt.set_span(span);
tt
};
let punct = |ch, spacing| at(TokenTree::Punct(Punct::new(ch, spacing)));
let mut message = Literal::string(&self.message);
message.set_span(span);
let tokens = [
punct(':', Spacing::Joint),
punct(':', Spacing::Alone),
at(TokenTree::Ident(Ident::new("core", span))),
punct(':', Spacing::Joint),
punct(':', Spacing::Alone),
at(TokenTree::Ident(Ident::new("compile_error", span))),
punct('!', Spacing::Alone),
at(TokenTree::Group(Group::new(
Delimiter::Brace,
TokenStream::from(TokenTree::Literal(message)),
))),
];
tokens.into_iter().collect()
}
}
pub(crate) type Result<T> = std::result::Result<T, Error>;
#[proc_macro_derive(Structio, attributes(structio))]
pub fn derive_structio(input: TokenStream) -> TokenStream {
match parse::parse(input).and_then(|input| emit::expand(&input)) {
Ok(tokens) => tokens,
Err(error) => error.into_compile_error(),
}
}