1
votes

Comment appeler une fonction Dyon intégrée à partir de Rust?

J'essaye d'appeler une fonction intégrée de Dyon ( sin ) depuis Rust:

Error: "Could not find function `sin`"

Cependant, j'obtiens

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

Que dois-je faire pour appeler correctement cette fonction?


0 commentaires

3 Réponses :


2
votes

Je ne peux pas expliquer les décisions de conception ici, mais call_str_ret gère uniquement les fonctions qui ont été chargées , pas fonctions externes ou intrinsèques .

Pour contourner le problème, vous pouvez charger une petite fonction shim qui appelle simplement la fonction appropriée:

XXX

Called sin - result F64(0.8939966636005579, None)


0 commentaires

2
votes

call_str ( ) ne s'intéresse qu'à un seul type d'appel de fonction. Je ne sais pas pourquoi ils font cela, mais une solution serait de le faire vous-même:

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 commentaires

0
votes

Les deux autres réponses m'ont conduit à une solution qui fonctionne parfaitement dans les deux cas: J'ai pris le Runtime.call_str_ret et l'ai modifié pour utiliser tout résultat non-None de module.find_function . IMO, le code est en fait plus propre que la version originale dans Runtime. J'ai soumis un PR pour cela qui a été fusionné, donc les versions de Dyon après 0.40.0 auront call_str_ret fonctionnant pour les fonctions intégrées.


Si vous ne pouvez pas utiliser une version plus récente de Dyon, vous pouvez alors appliquer manuellement le correctif à partir d'ici: https: // github .com / PistonDevelopers / dyon / pull / 582 .

Vous pouvez également utiliser votre propre version de call_str_ret, comme ceci:

Called sin - result F64(0.0, None)
Called sin_shim - result F64(0.0, None)
Error: "Could not find function `no_such`"

Cela vous permettra d'écrire le code original sous la forme

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

Ceci imprime:

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


0 commentaires