Procedural macros > execute an Expr or get Ident value

Sorry for my too short question indeed. Here is the simplified code on which I'm working (see below).

I created the say_hello!() compiler plugin which is basically calling HelloWorld::hello_world() by transforming a String literal into a type. I would now like to use that as part of a function using generics say_hello_untyped() getting the String from the function's generic T. I was planning to get the type name using unsafe { std::intrinsics::type_name::<T>() }; by the plugin fails to work because it is receiving an identifier (name) and not its String value.

When calling say_hello!("HelloWorld") the plugin receives

entry = expr(4294967295: "HelloWorld")
entry.node = Lit(Spanned { node: Str(HelloWorld(96), Cooked), span: Span { lo: BytePos(1130), hi: BytePos(1142), ctxt: #29 } })

And when calling say_hello!(name) the plugin receives (rightfully so):

entry = expr(4294967295: name)
entry.node = Path(None, path(name))

Thus, I would either need to be able to evaluate the expression in the proc_macro itself or chain the proc_macro calls in a way that the say_hello!() macro is called with a String value and not an identifier.

I hope it is clearer. Again sorry for my too short / unstructured question and thanks in advance for your help


client.rs

#![feature(core_intrinsics, plugin)]
#![plugin(my_plugin)]

trait SayHello {
    fn hello_world() -> String {
        "Hello world !!!".to_string()
    }    
}
struct HelloWorld;
impl SayHello for HelloWorld {}

macro_rules! say_hello_typed {
    ($generic:ty) => {
        <$generic>::hello_world()
    };
}

fn say_hello_typed<T: SayHello>() -> String {
    say_hello_typed!(T)
}

/* doesn't compile if uncommented
fn say_hello_untyped<T: ?Sized + 'static>() -> String {
    let name = unsafe { std::intrinsics::type_name::<T>() };
    say_hello!(name) // say_hello! is a compiler plugin from `my_plugins` crate
}
*/

fn main() {
    assert_eq!(say_hello_typed::<HelloWorld>(), "Hello world !!!".to_string());
    assert_eq!(say_hello!("HelloWorld"), "Hello world !!!".to_string());

    //assert_eq!(say_hello_untyped::<HelloWorld>(), "Hello world !!!".to_string()); // <-- doesn't compile
}

lib.rs from my_plugin crate

#![crate_type = "dylib"]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::Registry;
use syntax::ast::{self, Ident};
use syntax::codemap;
use syntax::ext::base::{self, ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{ Lit, Token };
use syntax::tokenstream;
use syntax::print::pprust;
use syntax::fold::Folder;

/// Compiler hook register plugins
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("say_hello",say_hello);
}

pub fn say_hello(ecx: &mut ExtCtxt, sp: codemap::Span, args: &[tokenstream::TokenTree]) -> Box<MacResult + 'static> {
    if let Some(type_name_str) = parse(ecx, sp.clone(), args) {
        let type_name_ident = Ident::from_str(type_name_str.as_str());
        let output = quote_expr!(ecx, {
            <$type_name_ident>::hello_world()
        });
        MacEager::expr(output)
    } else {
        ecx.parse_sess().span_diagnostic.err(format!("failure parsing type name from {:?}", &args).as_str());
        DummyResult::any(sp)
    }
}

/// Looks for a single String literal and returns it.
/// Otherwise, logs an error with `ecx.span_err` and returns None.
fn parse(ecx: &mut ExtCtxt, sp: codemap::Span, args: &[tokenstream::TokenTree]) -> Option<String> {
    let mut parser = ecx.new_parser_from_tts(args);

    if let Ok(expr) = parser.parse_expr() {
        let entry = ecx.expander().fold_expr(expr);
        println!("entry = {:?}", &entry);
        println!("entry.node = {:?}", &entry.node);

        match entry.node {
            ast::ExprKind::Lit(ref lit) => {
                match lit.node {
                    ast::LitKind::Str(ref s, _) => Some(s.to_string()),
                    _ => {
                        ecx.span_err(entry.span, &format!(
                            "expected string literal but got `{}`",
                            pprust::lit_to_string(&**lit)));
                        None
                    },
                }
            },
            _ => {
                ecx.parse_sess().span_diagnostic.err("unsupported arguments");
                None
            }
        }
    } else {
        ecx.parse_sess().span_diagnostic.err("unable to parse arguments");
        None
    }
}