问题
How do I take a vector of function argument AST variants, extract the values, and use them to instantiate a function call?
I am writing an interpreter that evaluates certain expressions. Some of the expressions are function calls. I am having a hard time figuring out how to translate the function calls AST to the actual call. The AST gives me the function name and a vector of arguments. I can lookup the function pointer to call from the name using a map, but passing the arguments to the function pointer is problem.
Rust does not have a splat operator (argument expansion). I could pass them as a tuple and use destructuring of the arguments, but I can't figure out how to convert the vector of AST argument enum variants to a tuple of the concrete types.
I can't simply map or loop over the AST arguments to extract the values and produce a tuple.
I can use nested tuples to build a heterogenous list incrementally:
fn prepend<I,T>(i: I, t: T) -> (I,T) { (i, t) }
fn foo() {
let x = ();
let x = prepend(1, x);
let x = prepend(2.0, x);
let x = prepend(true, x);
}
But that only works because x
gets shadowed and the new binding has a different type. This won't work:
fn foo() {
let mut x = ();
x = prepend(1, x);
x = prepend(2.0, x);
x = prepend(true, x);
}
Any ideas?
回答1:
You don't. Rust is a statically typed language and you are attempting to do non-statically-determinable actions.
Instead, all of your functions need to take in a collection of arguments, verify that there is the right number of arguments (and type, if appropriate to your interpreter), then call the appropriate Rust function with a fixed number of arguments:
// All of the panicking can be replaced by proper error handling.
enum Arg {
Bool(bool),
Int(i32),
}
impl Arg {
fn into_bool(self) -> bool {
match self {
Arg::Bool(b) => b,
_ => panic!("Not a bool"),
}
}
fn into_int(self) -> i32 {
match self {
Arg::Int(i) => i,
_ => panic!("Not an int"),
}
}
}
fn some_fn_wrapper(mut args: Vec<Arg>) {
assert_eq!(args.len(), 3);
let c = args.pop().unwrap();
let b = args.pop().unwrap();
let a = args.pop().unwrap();
some_fn(a.into_bool(), b.into_int(), c.into_bool())
}
fn some_fn(_a: bool, _b: i32, _c: bool) {}
All of this will happen at runtime, as you want to create a highly dynamic language.
See also:
- How do I pass each element of a slice as a separate argument to a variadic C function?
- How to pass a dynamic amount of typed arguments to a function?
- Calling a function only known at runtime
- How can I create a function with a variable number of arguments?
- Is Reflection possible in Rust, and if so how can I invoke an unknown function with some arguments?
来源:https://stackoverflow.com/questions/56856382/how-to-dynamically-build-function-calls-with-different-numbers-of-arguments-in-r