I want to directly execute the content of any string from user input in runtime, just like the eval or Function in javascript:
fn main() {
let args :Vec<String> = env::args().collect();
let input = &args[1];
// if input content is "aaa()", expect running:
// aaa();
// if input content is "aaa::bbb::ccc()", expect running:
// aaa::bbb::ccc();
// execute by macro_rules:
run!(input);
// or execute by proc_macro_attribute:
#[run(input)]
fn run_input(args :&String) {};
run_input(input);
}
Now I can parse the string to ast in macro_rules, proc_macro, proc_macro_attribute or proc_macro_hack, like following:
// parse in macro_rules:
#[macro_export]
macro_rules! run {
($input :expr) => {
let val = syn::parse_str::<syn::Expr>($input);
if let syn::Result::Ok(ast) = val {
// parse input ok
// want to execute the TokenStream of ast at here
} else {
// parse input error
};
}
}
// parse in proc_macro_attribute:
#[proc_macro_attribute]
pub fn run(
input :TokenStream,
func :TokenStream,
) -> TokenStream {
let output = quote! {
fn run_input(args :&String) {
let val = syn::parse_str::<syn::Expr>(args);
if let syn::Result::Ok(ast) = val {
// parse ok
// want to execute the TokenStream of ast at here
} else {
// parse error
};
}
};
output.into()
}
But I can't run any TokenStream of ast in runtime. So what should I do?
There is no direct easy equivalent to eval in JS.
Rust code gets compiled into machine code, so that your CPU can directly execute it.
You would need to replicate the same and just-in-time compile code and execute it. That's possible, but has a lot of overhead (you need to ship the whole compiler infrastructure to do that, also it won't give you access to other parts of your already existing code, so you will end up exposing a more constrained API that can be called.
The alternative is as ZiCog laid out: compile code into something else that's easier to execute. WebAssembly would be one possibility.
Rust doesn't have a virtual machine. At run time, none of the compiler machinery exists any more, and your executable doesn't even know how Rust looks like. Rust executable can't run Rust any better than a JavaScript program can run Rust. You could write code to a file, call the compiler, and then run the compiled executable. Of course it'd work only on machines that have Rust compiler installed, it'd be rather slow, and this code could not reference anything in your program.
Yes, Rust code can call the Rust compiler - if it is installed. In Rust the build machine and the target machine are two very different things. It is entirely possible to make a Rust executable that has a hard runtime dependency on the Rust compiler, and then those two compilers would be entirely unrelated, unlike eval where there is one interpreter that can do everything. The disadvantage is that users are required to install rustc before running your program.
In this way we see that Javascript is a superior language to Rust. JS can create new code, from input strings or whatever, and execute it. And that new code is totally integrated to what exists already. Possibly replacing what was there before.
As Mel said "What use is a program that cannot modify its own code?"
Wow, Dyon looks like an amazing piece of work. A cross between my favourite languages, Rust and Javascript. With some Go thrown in. One would guess that would be a horrible mess, hardly possible, but have to take it for a spin.
I love the non-goal: "Interfacing with other languages than Rust". No messing around there.
JS may be able to do it, but using its eval function is asking for security issues. In that sense it kind of tried to emulate lisp (where AFAICT the concept of an eval fn originated) but even less secure.