Hacker News new | ask | show | jobs
by matheusmoreira 3 days ago
How does it work internally? It would have to output the new source code as data somehow, and have the Rust compiler consume it. How does that happen?

The lispy "macros" I speak of are FEXPRs, just everyday normal functions that just happen to not evaluate their arguments, they receive the source code as lists instead. It's easy to manipulate those lists and evaluate the result.

Lisps themselves moved away from FEXPRs because they were "too powerful" and made the compiler's life hard. Common Lisp and Scheme macros are the more restricted versions that allow compilers to make more assumptions, thereby enabling more aggressive optimization.

2 comments

Rust has two form of macros: “macros by example” and “procedural macros.”

The latter is basically a function from token streams to token streams, and macros by example are more traditional macros which were initially designed by Dave Herman, who was heavily involved in Racket.

Yes, a Rust procedural macro is a function that takes a Rust syntax tree as an argument and returns a Rust syntax tree. When you use it, the compiler compiles it (for the host architecture), dynamically loads it into the compiler process, calls it, and inserts the output into the code to be compiled. https://doc.rust-lang.org/book/ch20-05-macros.html#procedura...

I don't see why this would inhibit optimization, unless you mean it slows down compilation, in which case, yep, that's a real and rather notorious downside.

> the compiler compiles it (for the host architecture), dynamically loads it into the compiler process, calls it, and inserts the output into the code to be compiled

That's actually amazing. So the compiler's own data structures are visible in the language.

I see how it works now. Thanks for explaining.