Please spell out what more about what you actually want to show to the user, and less of how you want to implement it
I’m not sure how all this stuff is supposed to look to the user. Here’s what I found in the Jai primer that you linked, that seems related:
That sounds like const fn, except that the restrictions have been lifted. Rust’s const fn needs to have those restrictions in order to make sure that the type system remains sound, since the compiler needs to be able to prove whether two types [T; 32] and [T; my_const_fn()] are the same type or not. Because Jai’s type system doesn’t actually promise to prove anything in particular (they “trust the programmer”), it doesn’t need this kind of restriction. #run directives don’t have any special APIs in Jai, assuming I’m correctly understanding the primer. They are just ordinary Jai code. The only reason they can introspect types is because Jai has ubiquitous RTTI/Reflection.
However, you’re describing a CompilerState struct and a Macro trait. The Jai primer describes nothing like that; that’s much closer to the kind of weird, special-case code that procedural macros use. How are they supposed to be exposed to the #run-ing code? If #run only works with code that is specially prepared for running at compile time, then how is it any different from procedural macros? Procedural macros do have access to the whole standard library, including file I/O.
Trying to imagine a trade-off between procedural macros and const functions, your trade-offs seem wrong, too:
The fact that macro rules are a new macro language is actually really nice when you’re writing simple stuff. It makes it a lot more terse, like regexes vs. manually parsing with bytes.
Can’t procedural macros in 2018 already do that? I know they can already pull in other libraries, like syn and quote…
Do you mean “explicitly accessed through a CompilerState” object, like proc macros, or “implicitly accessed by calling types and functions”, like what the Jai primer described? This is where my confusion about the whole post comes from; what will all this look like from a user’s perspective?
That can be added to existing proc macros. That’s not actually an advantage of any new metaprogramming API; it’s a feature that can, and should, be added to rustc for what’s already there.
How much API surface are you asking to expose here? Because this sounds like a long, long, long series of RFCs.
Procedural macros and Cargo build scripts already run arbitrary code on the build machine with no sandboxing.
Just for clarity, we don’t just want purity. It is also important that any methods of hooking into the compiler should be ordering-agnostic. let output_source = run_1(run_2(input_source)) and let output_source = run_2(run_1(input_source)) aren’t necessarily the same result.