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

Я пытаюсь вызвать встроенную функцию Dyon (sin) из Rust:

use dyon::{Module, Runtime, Variable};
use std::sync::Arc;

fn main() {
    let mut dyon_runtime = Runtime::new();
    let module = Module::new();
    let dyon_module = Arc::new(module);
    let v = dyon_runtime.call_str_ret("sin", &[Variable::f64(0.0)], &dyon_module);
    match v {
        Err(e) => {
            eprintln!("Error: {:?}", e);
        }
        Ok(v) => {
            println!("Called sin - result {:?}", v);
        }
    };
}

Однако я получаю

Error: "Could not find function `sin`"

Что мне нужноправильно ли вызывать эту функцию?

Ответы [ 3 ]

0 голосов
/ 22 января 2019

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

use dyon::{ast, Module, Runtime, Variable};
use range::Range;
use std::cell::Cell;
use std::sync::Arc;

fn main() {
    let mut dyon_runtime = Runtime::new();
    let module = Module::new();

    let name: Arc<String> = Arc::new("sin".into());
    let f_index = Cell::new(module.find_function(&name, 0));
    let args = vec![ast::Expression::Variable(Box::new((
        Range::empty(0),
        Variable::F64(1.0, None),
    )))];
    let call = ast::Call {
        alias: None,
        name,
        f_index,
        args,
        custom_source: None,
        source_range: Range::empty(0),
    };
    let dyon_module = Arc::new(module);
    println!("{:?}", dyon_runtime.call(&call, &dyon_module));
}
0 голосов
/ 22 января 2019

Оба других ответа привели меня к решению, которое работает чисто для обоих случаев: я взял Runtime.call_str_ret и изменил его, чтобы использовать любой не-None результат из module.find_function.ИМО код на самом деле чище, чем оригинальная версия во время выполнения.Я представил PR для этого, который был объединен, поэтому в выпусках Dyon после 0.40.0 call_str_ret будет работать для встроенных функций.


Если вы не можете использовать болеепоследняя версия Dyon, тогда вы можете вручную применить патч отсюда: https://github.com/PistonDevelopers/dyon/pull/582.

или вы можете использовать свою собственную версию call_str_ret, например так:

use dyon::{Module, Runtime, Variable};
use std::sync::Arc;

extern crate range;

/// Call function by name, returning a value.
pub fn call_str_ret_ex(
    runtime:&mut Runtime,
    function: &str,
    args: &[Variable],
    module: &Arc<Module>
) -> Result<Variable, String> {
    use std::cell::Cell;
    use range::Range;
    use dyon::FnIndex;
    use dyon::runtime::Flow;
    use dyon::ast;

    let name: Arc<String> = Arc::new(function.into());
    let fn_index = module.find_function(&name, 0);
    if let FnIndex::None = fn_index {
        return Err(format!("Could not find function `{}`",function))
    }

    let call = ast::Call {
        alias: None,
        name: name.clone(),
        f_index: Cell::new(fn_index),
        args: args.iter()
                .map(|arg| ast::Expression::Variable(Box::new((
                            Range::empty(0), arg.clone()))))
                .collect(),
        custom_source: None,
        source_range: Range::empty(0),
    };
    match runtime.call(&call, &module) {
        Ok((Some(val), Flow::Continue)) => Ok(val),
        Err(err) => Err(err),
        _ => Err("Error during call".to_owned())
    }
}

Это позволитВы пишете оригинальный код как

def test_dyon_fn(
    dyon_runtime: &mut Runtime
    module: &Module,
    fn: &str,
)
    let v = call_str_ret_ex(&mut dyon_runtime, fn, &[Variable::f64(0.0)], &dyon_module);
match v {
    Err(e) => {
        eprintln!("Error: {:?}", e);
    }
    Ok(v) => {
        println!("Called {:?}  - result {:?}", fn, v);
    }
};

fn main() {
    let mut dyon_runtime = Runtime::new();
    let mut module = Module::new();
    let shim = Arc::new("sin_shim(x) = sin(x)".into());
    dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
    let dyon_module = Arc::new(module);

    test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin");
    test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin_shim");
    test_dyon_fn(&mut dyon_runtime, &dyon_module, "no_such");
}

Это печатает:

Called sin - result F64(0.0, None)
Called sin_shim - result F64(0.0, None)
Error: "Could not find function `no_such`"
0 голосов
/ 22 января 2019

Я не могу объяснить здесь проектные решения, но call_str_ret обрабатывает только те функции, которые были загружены , а не внешние функции или встроенные функции .

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

use dyon::{Module, Runtime, Variable};
use std::sync::Arc;

fn main() {
    let mut dyon_runtime = Runtime::new();
    let mut module = Module::new();

    let shim = Arc::new("do_it(x) = sin(x)".into());
    dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
    let dyon_module = Arc::new(module);

    let v = dyon_runtime.call_str_ret("do_it", &[Variable::f64(90.0)], &dyon_module);
    match v {
        Err(e) => {
            eprintln!("Error: {:?}", e);
        }
        Ok(v) => {
            println!("Called sin - result {:?}", v);
        }
    };
}
Called sin - result F64(0.8939966636005579, None)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...