Let macros take any TokenTree as input

edit: there was an RFC for this and it has been rejected. Short Macro Invocation Syntax: m!123 and m!"abc" by m-ou-se · Pull Request #3267 · rust-lang/rfcs · GitHub

Rust parses macros by expecting the following sequence:

  • TokenTree::Ident (the m)
  • TokenTree::Punct('!') (the )
  • TokenTree::Group.

You can invoke macros in 3 forms, which are TokenTree::Group:

  • m!()
  • m![]
  • m!{}

I believe there is no reason why the 3rd TokenTree must be a TokenTree::Group specifically? Removing this restriction will allow us to write more expressive macros when the macro input itself is very simple, (by dropping parentheses)

Some ideas off the top of my head:

  • bigint!100ee4 to create a large number
  • f!"my name is {name}" python-like f-strings
  • o!"heap-allocated string"
  • d!"dedented string literal" could be written in user-code and be ergonomic enough to totally replace the RFC RFC: Dedented String Literals by nik-rev · Pull Request #3830 · rust-lang/rfcs · GitHub
  • len!10km + len!50ft could be nice. and css!100px + css!4rem
  • color!ff00aa
  • regex!"\d{3}-\d{2}-\d{4}".search(str) compile-time regex
  • env!MY_ENV_VAR
  • uuid!"550e8400-e29b-41d4-a716-446655440000" parses the UUID at compile-time
  • icon!"svgs/loading.svg" parses the SVG file at compile-time and expands to an Icon
  • stuff like c!"c-string" and b!'?' byte chars could be implemented in user-code
  • For TokenTree::Punct I thought about syn's Token![,] macro and how it could be written as Token!, but that doesn't look right so maybe forbid TokenTree::Punct

The input of the macros is still TokenStream with a single TokenTree::Literal or TokenTree::Ident

1 Like

For all of these category I think that macros are just fundamentally the wrong approach. Things shouldn't be working at token level when they could be working at the normal syntax grammar level just fine.

We should have things like "550e8400-e29b-41d4-a716-446655440000":Uuid and 1234:BigInt via some const trait From{String,Integer}Literal traits instead of hacking it with macros.

That's the path to better inference too, like takes_nonzero_u8(3) just working and takes_nonzero_u8(0) being a compile-time error.

This is a job for CTFE, not for macros.

Especially because then you have much nicer import behaviour, rather than lots of people making their own o! macros that all conflict -- see C++ suffixes

7 Likes

This was previously proposed and rejected:

That does not mean the feature cannot ever be added in the future, but a new proposal should have specific answers to the concerns raised with the previous one.

5 Likes