Как динамически создавать вызовы функций с различным количеством аргументов в Rust? - PullRequest
0 голосов
/ 02 июля 2019

Как взять вектор вариантов AST аргумента функции, извлечь значения и использовать их для создания экземпляра вызова функции?

Я пишу переводчик, который оценивает определенные выражения. Некоторые выражения являются вызовами функций. Мне трудно понять, как перевести вызовы функций AST в фактический вызов. AST дает мне имя функции и вектор аргументов. Я могу найти указатель функции для вызова по имени, используя карту, но передача аргументов указателю на функцию является проблемой.

В Rust нет оператора splat (расширение аргумента). Я мог бы передать их как кортеж и использовать деструктуризацию аргументов, но я не могу понять, как преобразовать вектор вариантов перечисления аргументов AST в кортеж конкретных типов.

Я не могу просто отобразить или перебрать аргументы AST для извлечения значений и создания кортежа.

Я могу использовать вложенные кортежи для постепенного построения гетерогенного списка:

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);
}

Но это работает только потому, что x затеняется, а новая привязка имеет другой тип. Это не сработает:

fn foo() {
    let mut x = ();
    x = prepend(1, x);
    x = prepend(2.0, x);
    x = prepend(true, x);
}

Есть идеи?

1 Ответ

0 голосов
/ 02 июля 2019

Ты не. Rust - это статически типизированный язык, и вы пытаетесь выполнить нестатически определяемые действия.

Вместо этого все ваши функции должны принимать набор аргументов, проверять, есть ли правильное количество аргументов (и вводить, если это соответствует вашему интерпретатору), затем вызывать соответствующую функцию Rust с фиксированным числом аргументов. :

// 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) {}

Все это произойдет во время выполнения, так как вы хотите создать высокодинамичный язык.

Смотри также:

...