How to execute any string as source code in runtime?

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?

1:
Accept users Rust source code input.
Compile that Rust to web assembly.
Run that web assembly from your normally compiled Rust program.

2:
Use Deno: How to Compile Rust into WebAssembly and Run it Deno

1 Like

Executing user input is almost always a bad idea.

9 Likes

To answer this a bit more broadly:

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.

3 Likes

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.

3 Likes

Everything previous posters have said is true, but if you're determined you can use evcxr to fake it: https://crates.io/crates/evcxr

7 Likes

Yeah, everything is machine code, include rust compiler.
I think maybe there are any ways to call rust compiler in the rust program running lifecycle.

Maybe this is a usable way in reserve.

But the rust compiler executable knows, if there are any.

But JS can call rust compiler, so rust executable can call rust compiler right?

Reading from file is the equivalent of reading from input I think.

Yes indeed, bad and dangerous, this only is a test. : )

Oh, it looks nice at first sight! :star_struck:

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?"

http://catb.org/jargon/html/story-of-mel.html

:slight_smile:

1 Like

That's because Javascript always requires its "compiler" to be installed in order to run while Rust doesn't.

2 Likes

Indeed so.

That's just an implementation detail :slight_smile:

Hi,
since nobody here recommended it, try taking a look at the Rusty dynamically typed scripting language Dyon.

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.

Thanks for the heads up on Dyon.

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.

1 Like

Fortunately modern JS offers a much safer and better performing replacement for eval.

let funcStr = `
    return x * y;
`
let func = new Function("x", "y", funcStr)
result = func(10, 20)
console.log(result)

That's not "much safer" - in fact it's just eval but in a function context. Try new Function("x", "y", "alert(1);")(10, 20).

1 Like