Both of the other answers led me to a solution that works cleanly for both cases:
I took the Runtime.call_str_ret
and modified it to use any non-None result from module.find_function
. IMO the code is actually cleaner than the original version in Runtime. I've submitted a PR for this which has been merged, so releases of Dyon after 0.40.0 will have call_str_ret
working for built-in functions.
If you can't use a more recent version of Dyon, then you could manually apply the patch from here: https://github.com/PistonDevelopers/dyon/pull/582.
Or alternatively you could use your own version of call_str_ret, like this:
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())
}
}
This will let you write the original code as
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");
}
This prints:
Called sin - result F64(0.0, None)
Called sin_shim - result F64(0.0, None)
Error: "Could not find function `no_such`"