Single quote used as a tick in macros

I'm interested in writing a crate that processes Rubik's cube moves. I'd like to be able to create a macro that can take a set of moves like R U R' U and produce a Vec<Move>.

However, if I were to write something like that:

let my_moves = moves!(R U R' U);

I get compile errors because the compiler thinks that the ' is the start of a string. I know I could wrap everything in a string and have a regular function like:

let my_moves = moves("R U R' U");

but is there a way I could write a macro that could take that kind of input without getting the compiler angry, or do I just need to wrap it in a string?

1 Like

There is no way to do that by itself, even with a procedural macro. This is because the macro body must still be able to be parsed to the AST, and the single quote won't let you do that.

I know it's not the correct notation, but you could do R-. That would work and could still be matched on. It shouldn't be too difficult to write, as there's not that many moves, even once you take into account rotations, wide turns, and slices.

I will note that if you intend to permit commutations, things will get a fair bit more difficult to accomplish with a macro_rules! macro.

2 Likes

FWIW, you could probably do

let my_moves = moves!(R U 'R U);

using the lifetime matcher.

But that's probably too cute, and something like moves!(R U R! U) instead, as jhpratt mentioned, might be better.

1 Like

Just a note: I'm approaching this as someone who knows the notation well and has attended a couple competitions. I suspect most people on this forum don't have knowledge of both cubing and Rust macros.

Using a lifetime would work, but doing so would require whitespace before it. It's quite common to not have whitespace in notation.

1 Like

Thanks for all the input! I didn't think about it from the view of the AST. From that point of view, it's obvious that using macros wouldn't work. It's more important to me to be able to keep the ' than to not surround things with some "s. Plus, then I can write functions instead of macros, haha

There is another option, in principle: write a macro that takes a path to a file containing code writteb in your DSL, opens and reads that file, parses and processes the DSL code within, and then proceeds as a normal macro would.

This would give you:

  • The ability to use A' as an identifier
  • The ability to avoid putting that in a string

And the cost would be:

  • You'd need to write a grammar or parser (eg using pest, nom etc) rather than bring able to rely on e.g. the syn and quote crates. This is so that you can define your identifier format to allow ending in 0 or more ', eg the tegex [A-Za-z_][A-Za-z0-9_]*\'*
  • An inability to write inline code (i.e. code located within a .rs file) that is not encased in a Rust string

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.