Using quote and proc_macro2 in main.rs?

Hi!

I'm trying to create a code generator using the quote crate, but I'm having difficulty using the proc_macro2 crate.

Using quote! in main.ts seems to work fine:

// example usage: cargo build | rustc -o hello -
use quote::quote;

fn main() {
    let tokens = quote! {
        fn main() {
            println!("Hello, world!");
        }
    };
    println!("{}", tokens);
}

The trouble happens when I try to return the result of quote! from a function. Based on the quote docs, it seems like I should be converting it to a proc_macro2::TokenStream like so:

use proc_macro2::TokenStream;
use quote::quote;

fn gen_hello() -> TokenStream {
    let tokens = quote! {
        fn main() {
            println!("Hello, world!");
        }
    };
    TokenStream::from(tokens)
}

fn main() {
    println!("{}", gen_hello());
}

But, I get the following error when I run cargo run:

thread 'main' panicked at 'procedural macro API is used outside of a procedural macro'

Does anyone have experience using quote! in main.rs? How do you get around this issue?

Thanks!

EDIT:

Seems like I can work around it by using quote::__private::TokenStream, but that feels wrong. The quote docs state:

proc_macro2 types may exist anywhere including tests and non-macro code like main.rs and build.rs

EDIT2:

Doh, looks like I don't need to call from :woman_facepalming:

use proc_macro2::TokenStream;
use quote::quote;

fn gen_hello() -> TokenStream {
    quote! {
        fn main() {
            println!("Hello, world!");
        }
    }
}

So..., you are trying to call proc-macro from a binary? currently, that is not possible on rust, if you want to use procedural macros you have to define it in a crate designed for that purpose, that crate must be a library and you would write on its Cargo.toml:

[lib]
proc-macro = true

I recommend reading the book about this topic, also you can work with multiple crates for the same project defining a workspace.

This example works in the Playground as-is. However, you shouldn't convert quote! output to proc_macro2::TokenStream, since this output is already proc_macro2::TokenStream - the conversion is a no-op. What is suggested by quote docs is converting to proc_macro::TokenStream (note, no 2 in here), since this is what you have to return from procedural macro, but this type can't be used without the procedural macro - hence the panic.

1 Like