use std::mem;
use data::DataSourceError;
use super::*;
use crate::lang::{VarAccessMode};
pub fn alt(vm: &mut VM, (a, mut b): (RantValue, RequiredVarArgs<RantValue>)) -> RantStdResult {
if !a.is_nothing() {
vm.cur_frame_mut().write(a);
Ok(())
} else {
for val in b.drain(..) {
if !val.is_nothing() {
vm.cur_frame_mut().write(val);
break
}
}
Ok(())
}
}
pub fn call(vm: &mut VM, (func, args): (RantFunctionHandle, Option<Vec<RantValue>>)) -> RantStdResult {
vm.push_val(RantValue::Function(Rc::clone(&func)))?;
let argc = args.as_ref().map(|args| args.len()).unwrap_or(0);
if let Some(mut args) = args {
for arg in args.drain(..).rev() {
vm.push_val(arg)?;
}
}
vm.cur_frame_mut().push_intent(Intent::Call { argc, override_print: false });
Ok(())
}
pub fn cat(vm: &mut VM, mut args: VarArgs<RantValue>) -> RantStdResult {
let frame = vm.cur_frame_mut();
for val in args.drain(..) {
frame.write(val);
}
Ok(())
}
pub fn print(vm: &mut VM, mut args: VarArgs<RantValue>) -> RantStdResult {
if args.len() < 2 {
let frame = vm.cur_frame_mut();
for val in args.drain(..) {
frame.write(val);
}
} else if let Some(frame) = vm.parent_frame_mut(1) {
for val in args.drain(..) {
frame.write(val);
}
}
Ok(())
}
pub fn copy(vm: &mut VM, val: RantValue) -> RantStdResult {
vm.cur_frame_mut().write(val.shallow_copy());
Ok(())
}
pub fn either(vm: &mut VM, (cond, a, b): (bool, RantValue, RantValue)) -> RantStdResult {
let val = if cond { a } else { b };
vm.cur_frame_mut().write(val);
Ok(())
}
pub fn fork(vm: &mut VM, seed: Option<RantValue>) -> RantStdResult {
let rng = match seed {
Some(RantValue::Int(i)) => vm.rng().fork_i64(i),
Some(RantValue::String(s)) => vm.rng().fork_str(s.as_str()),
Some(other) => runtime_error!(RuntimeErrorType::ArgumentError, "seeding fork with '{}' value is not supported", other.type_name()),
None => vm.rng().fork_random(),
};
vm.push_rng(Rc::new(rng));
Ok(())
}
pub fn type_(vm: &mut VM, val: RantValue) -> RantStdResult {
vm.cur_frame_mut().write_frag(val.type_name());
Ok(())
}
pub fn unfork(vm: &mut VM, _: ()) -> RantStdResult {
if vm.pop_rng().is_none() {
runtime_error!(RuntimeErrorType::InvalidOperation, "cannot unfork root seed");
}
Ok(())
}
pub fn tap(vm: &mut VM, _: VarArgs<RantNothing>) -> RantStdResult {
Ok(())
}
pub fn seed(vm: &mut VM, _: ()) -> RantStdResult {
let signed_seed = unsafe {
mem::transmute::<u64, i64>(vm.rng().seed())
};
let frame = vm.cur_frame_mut();
frame.write(RantValue::Int(signed_seed));
Ok(())
}
pub fn len(vm: &mut VM, val: RantValue) -> RantStdResult {
vm.cur_frame_mut().write(val.len().try_into_rant().into_runtime_result()?);
Ok(())
}
pub fn error(vm: &mut VM, msg: Option<String>) -> RantStdResult {
const DEFAULT_ERROR_MESSAGE: &str = "user error";
Err(RuntimeError {
error_type: RuntimeErrorType::UserError,
description: msg,
stack_trace: None,
})
}
pub fn range(vm: &mut VM, (a, b, step): (i64, Option<i64>, Option<u64>)) -> RantStdResult {
let step = step.unwrap_or(1);
let range = if let Some(b) = b {
RantRange::new(a, b, step)
} else {
RantRange::new(0, a, step)
};
vm.cur_frame_mut().write(range);
Ok(())
}
pub fn irange(vm: &mut VM, (a, b, step): (i64, Option<i64>, Option<u64>)) -> RantStdResult {
let step = step.unwrap_or(1);
let range = if let Some(b) = b {
RantRange::new(a, b + if a <= b { 1 } else { -1 }, step)
} else {
RantRange::new(0, a + if a >= 0 { 1 } else { -1 }, step)
};
vm.cur_frame_mut().write(range);
Ok(())
}
pub fn require(vm: &mut VM, module_path: String) -> RantStdResult {
if let Some(module_name) =
PathBuf::from(&module_path)
.with_extension("")
.file_name()
.map(|name| name.to_str())
.flatten()
.map(|name| name.to_owned())
{
if let Some(cached_module) = vm.context().get_cached_module(&module_name) {
vm.def_var_value(module_name.as_str(), VarAccessMode::Descope(1), cached_module, true)?;
return Ok(())
}
let dependant = Rc::clone(vm.cur_frame().origin());
let module_resolver = Rc::clone(&vm.context().module_resolver);
match module_resolver.try_resolve(vm.context_mut(), module_path.as_str(), Some(dependant.as_ref())) {
Ok(module_program) => {
vm.cur_frame_mut().push_intent(Intent::ImportLastAsModule { module_name, descope: 1 });
vm.push_frame_flavored(Rc::clone(&module_program.root), StackFrameFlavor::FunctionBody)?;
Ok(())
},
Err(err) => runtime_error!(RuntimeErrorType::ModuleError(err)),
}
} else {
runtime_error!(RuntimeErrorType::ArgumentError, "missing module name from path: {}", module_path);
}
}
pub fn try_(vm: &mut VM, (context, handler): (RantFunctionHandle, Option<RantFunctionHandle>)) -> RantStdResult {
vm.push_unwind_state(handler);
vm.cur_frame_mut().push_intent(Intent::DropStaleUnwinds);
vm.call_func(context, vec![], false)?;
Ok(())
}
pub fn ds_request(vm: &mut VM, (dsid, args): (InternalString, VarArgs<RantValue>)) -> RantStdResult {
match vm.context().data_source(dsid.as_str()) {
Some(ds) => {
let result = ds.request_data(args.into_vec()).into_runtime_result()?;
vm.cur_frame_mut().write(result);
},
None => {
runtime_error!(RuntimeErrorType::DataSourceError(DataSourceError::User(format!("data source '{}' not found", &dsid))))
}
}
Ok(())
}
pub fn ds_query_sources(vm: &mut VM, _: ()) -> RantStdResult {
let sources = vm.context().iter_data_sources().map(|(id, _)| id.into_rant()).collect::<RantList>();
vm.cur_frame_mut().write(sources);
Ok(())
}