5

I'm using a library for string interning (string-cache), that uses macros to efficient create elements (atom!). However for simplification here is a similar macro that demonstrates the problem

macro_rules! string_intern {
   ("d") => ("Found D");
}

say I need to call this macro from another macro and give it a string version of an identifier.

macro_rules! print_ident {
    ($id:ident) => (
        string_intern!(stringify!($id));
    );
}

However calling this macro

fn main() {
    print_ident!(d);
}

Fails with error:

error: no rules expected the token `stringify`
 --> <anon>:7:24
  |
7 |         string_intern!(stringify!($id));
  |                        ^^^^^^^^^

Playground link

I know stringify! correctly converts to identifier d to string "d", because giving it to println! works as expected. Is there a way to pass the identifier I want turned into string to string_intern?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Daniel Fath
  • 16,453
  • 7
  • 47
  • 82

2 Answers2

10

println! lets you do this because it uses format_args! under the covers, which is a compiler-provided "intrinsic" that forcibly evaluates its first argument before using it. You cannot do this from a user-defined macro; you'd have to write a compiler plugin (which requires a nightly compiler and no guarantee of stability).

So, yeah; you can't. Sorry. The only thing you can do is redefine the macro in such a way that you don't need an actual string literal, or change how you invoke it.

DK.
  • 55,277
  • 5
  • 189
  • 162
1

Your definition of string_intern! is expecting a literal "d" and nothing else, but you are passing in these tokens: stringify, !, ... which why it fails. The definition of string_intern! that you want is probably:

macro_rules! string_intern {
    ($e:expr) => {
        match $e {
            "d" => "Found D",
            _ => "Not found",
        }
    }
}

which can accept any expression that evaluates to a string type.

John
  • 1,856
  • 2
  • 22
  • 33
  • 1
    It's just a shorthand. Basically, I can't ask of you to download `string-cache` to solve this example, so this is MVP for this problem. – Daniel Fath Oct 02 '16 at 12:49
  • @DanielFath Ah! I guess I didn't understand your intention correctly... So you absolutely wanted compile-time matching... – John Oct 02 '16 at 12:58