9

I am starting out learning Rust macros, but the documentation is somewhat limited. Which is fine — they're an expert feature, I guess. While I can do basic code generation, implementation of traits, and so on, some of the built-in macros seem well beyond that, such as the various print macros, which examine a string literal and use that for code expansion.

I looked at the source for print! and it calls another macro called format_args. Unfortunately this doesn't seem to be built in "pure Rust" the comment just says "compiler built-in."

Is it possible to write something as complex as print! in a pure Rust macro? If so, how would it be done?

I'm actually interested in building a "compile time trie" -- basically recognizing certain fixed strings as "keywords" fixed at compile time. This would be performant (probably) but mostly I'm just interested in code generation.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Richard Rast
  • 1,772
  • 1
  • 14
  • 27
  • The official documentation may be "somewhat limited", but have you looked at [the little book of Rust macros](https://danielkeep.github.io/tlborm/book/index.html)? – Jmb May 28 '18 at 07:05
  • @Jmb no, that's new to me. Thanks – Richard Rast May 28 '18 at 11:14

2 Answers2

4

format_args is implemented in the compiler itself, in the libsyntax_ext crate. The name is registered in the register_builtins function, and the code to process it has its entry point in the expand_format_args function.

Macros that do such detailed syntax processing cannot be defined using the macro_rules! construct. They can be defined with a procedural macro; however, this feature is currently unstable (can only be used with the nightly compiler and is subject to sudden and unannounced changes) and rather sparsely documented.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
2

Rust macros cannot parse string literals, so it's not possible to create a direct Rust equivalent of format_args!.

What you could do is to use a macro to transform the function-call-like syntax into something that represents the variadic argument list in the Rust type system in some way (say, as a heterogeneous single-linked list, or a builder type). This can then be passed to a regular Rust function, along with the format string. But you will not be able to implement compile-time type checking of the format string this way.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • If this is so, then how does (e.g.) diesel work? It seems to generate quite extensive code for a schema from a single macro invocation, which seems to even talk to the database to get that information. Yet diesel is not part of rust -- right? – Richard Rast May 26 '18 at 20:27
  • It uses custom `derive`, which allows you to generate Rust code (by writing Rust code), but that takes structs/enums/unions as input. So it's still not powerful enough to implement something like `format_args!`. – Florian Weimer May 26 '18 at 21:58