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?
3 Réponses :
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)
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)); }
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()) } }