ivandardi / RustbotPython

A Discord bot for the Community Rust Language server, written in Python.
MIT License
16 stars 9 forks source link

Handle ?eval code generation differently #26

Open kangalio opened 3 years ago

kangalio commented 3 years ago

Problem

Currently, the code provided to the ?eval command is wrapped like this:

fn main() {
    println!("{:?}", {
        // CODE HERE
    });
}

This has a small issue; when the code evaluates to a value with a lifetime, the code fails to compile, for example:

fn main() {
    println!("{:?}", {
        let a = 42;
        &a
    });
}

That's because &a exits the scope we explicitly declared with {}, but its lifetime is bound to something within that scope (a).

This is slightly confusing for bot users and also a bit annoying.

How to fix

You may be able to prevent this issue by wrapping the code differently. The following ?eval input...

/* line 1 */;
/* line 2 */;
/* line 3 */;
/* line 4 */

...would be translated to the following Rust code...

fn main() {
    /* line 1 */;
    /* line 2 */;
    /* line 3 */;
    println!("{:?}", /* line 4 */);
}

In other words: the code will be split up by semicolons and only the result of the last line is put into the println!(). The rest are top-level statements inside main.

I'm not sure if there are edge cases in which this approach would break

kangalio commented 3 years ago

Naively splitting by semicolons would break quite quickly, for example when putting semicolons in colons or in strings. A more robust way would be to parse the source code using something like syn. This brings plenty problems though:

This all seems quite clunky and error prone. Does someone have an idea how to do it better?