Оба других ответа привели меня к решению, которое работает чисто для обоих случаев: я взял 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`"