I want to embed a tiny programming language in Rust by using procedural macro, but a macro call cannot communicate with others at different call places, so variables can't be shared. Any solutions? Thanks.
For instance:
fn main() {
call! {
let a = 10;
}
call! {
let b = a; // How to let it knows `a` as `a` is not a Rust variable?
}
}
macros are hygienic, identifiers (e.g. a variable name) from one macro is never the same as identifiers from another macro. if you need this, the identifier tokens must be created outside the macro and passed as arguments to the macros. example:
Thanks but I'm not saying macro_rules, if I understand correctly the procedural macro is defined by a divided crate.
I want these macros to communicate not through rust's features, like local TCP servers etc.
well, if you are talking about procedural macros, they are not hygienic at all, theyjust transform syntactical tokens.
I think I don't understand your question well. from your example code, I thought you just want to create a variable in one macro invocation, then use the variable in another. procedural macros can do this without any problem.
but apparently, you have something different in mind. what do you mean by "communicating"? please explain your intention in detail, or show a concrete example, so we can understand your problem better.
This is technically possible, since procedural macros are normal Rust code and can use anything, but highly discouraged and unreliable. Macros are expected to be pure and not do anything other then shuffle tokens around; if they have any state (internal or external), they will often break due to incremental compilation, and if they're using some external resource, this can (and probably will) be treated as potential security hazard.
What is the output you want your macro generation to produce in this scenario? I'm asking about both the generated Rust output and any other outputs (including stdout/stderr messages) you would want to see.
Macros cannot communicate. They run conceptually, if not in practice, in isolated environments, in parallel, with no fixed order. Macros communicating with macros is neither possible nor desirable. Technically macros are not (currently) sandboxed, and so they can use any OS-level standard primitives for communication. In practice, since they can expand in arbitrary order, you can't really make it work. Also, macro expansion must be idempotent and side-effect free, since the same macro can be expanded multiple times for any reason (e.g. a user in an IDE can just expand your macro to view its output, without touching any other macros).
Proc macros are not hygienic, but unless you want your code to break in wonderful and exciting ways, you really should just be enforcing hygiene on your own rather than abusing its non-existence. This means if you need a shared identifier, you really should just pass its name to the macros explicitly, just like you would do with macro_rules!.
Now I understand that: procedural macros do have the ability to use any tools outside Rust, but since proc macro may be execute an uncontrollable number of times in uncontrollable places and time, so the expanded content will become unpredictable if using side-effects. So the conclusion is it's able but better not do that.
But I have another question: As we have macros like env! and file! in std that can read controllable outside environments, do we have this possibility: we put a file (a JSON file, for example) in a crate, then use a macro to "link" it, so that crates dependent on this parent crate can see the "linked" (JSON) file's content at compile time.
I don't think I understand what you're trying to do. Indeed, why doesn't include_str! solve your issue? Macros can't do compile-time introspection, so unless you explicitly pass that string item into a macro, no one can look at its value. And even if some macro would do it, why is it an issue?
To make some optimization. I understand that this need is rather niche, but it would be great if it could be done. For example, computing the effect of multiple CSS code segments on an element at compile time. It's hard to solve this problem using constant computation.
when we call _private! in crate B, we indirectly call my_macro2!, only in this way my_macro2! could see the file's content.
I wonder whether put file content in the environment variable would work and how to? Does rustc reserve environment variables during incremental compilation?
There is Inventory which let's you do magical things. But it works via linker magic, hence is not portable (e.g. fails on Web/Wasm).
This is used in TypeTag.
proc macros don't need to be pure in their implementation, only in their behavior
as long as each input of tokens can only yield a single output, it doesn't matter if it technically does impure operations like caching valurs in static variables.