#[cfg(feature = "test-hooks")]
use crate::{
args::ArgValues,
exception_private::{ExcType, ExcTypeExt, RunResult},
modules::ModuleFunctions,
};
use crate::{
bytecode::VM,
heap::{HeapData, HeapId},
intern::StaticStrings,
types::{Module, NamedTuple},
value::{Marker, Value},
};
#[cfg(feature = "test-hooks")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, serde::Serialize, serde::Deserialize)]
#[strum(serialize_all = "lowercase")]
pub(crate) enum SysFunctions {
Setrecursionlimit,
}
pub fn create_module(vm: &mut VM<'_>) -> HeapId {
let mut module = Module::new(StaticStrings::Sys);
module.set_attr(StaticStrings::Platform, StaticStrings::Monty.into(), vm);
module.set_attr(StaticStrings::Stdout, Value::Marker(Marker(StaticStrings::Stdout)), vm);
module.set_attr(StaticStrings::Stderr, Value::Marker(Marker(StaticStrings::Stderr)), vm);
module.set_attr(StaticStrings::Version, StaticStrings::MontyVersionString.into(), vm);
let version_info = NamedTuple::new(
StaticStrings::SysVersionInfo,
vec![
StaticStrings::Major.into(),
StaticStrings::Minor.into(),
StaticStrings::Micro.into(),
StaticStrings::Releaselevel.into(),
StaticStrings::Serial.into(),
],
vec![
Value::Int(3),
Value::Int(14),
Value::Int(0),
Value::InternString(StaticStrings::Final.into()),
Value::Int(0),
],
);
let version_info_id = vm.heap.allocate(HeapData::NamedTuple(Box::new(version_info)));
module.set_attr(StaticStrings::VersionInfo, Value::Ref(version_info_id), vm);
#[cfg(feature = "test-hooks")]
module.set_attr(
StaticStrings::Setrecursionlimit,
Value::ModuleFunction(ModuleFunctions::Sys(SysFunctions::Setrecursionlimit)),
vm,
);
vm.heap.allocate(HeapData::Module(Box::new(module)))
}
#[cfg(feature = "test-hooks")]
pub(super) fn call(vm: &mut VM<'_>, function: SysFunctions, args: ArgValues) -> RunResult<Value> {
match function {
SysFunctions::Setrecursionlimit => setrecursionlimit(vm, args),
}
}
#[cfg(feature = "test-hooks")]
fn setrecursionlimit(vm: &mut VM<'_>, args: ArgValues) -> RunResult<Value> {
let arg = args.get_one_arg("sys.setrecursionlimit", vm.heap)?;
let Value::Int(limit) = arg else {
arg.drop_with(vm);
return Err(ExcType::type_error("sys.setrecursionlimit() argument must be int"));
};
let Ok(new_limit) = usize::try_from(limit) else {
return Err(ExcType::value_error("recursion limit must be greater or equal than 1"));
};
if new_limit == 0 {
return Err(ExcType::value_error("recursion limit must be greater or equal than 1"));
}
match vm.heap.tracker().lower_recursion_limit(new_limit) {
Ok(()) => Ok(Value::None),
Err(current) => Err(ExcType::value_error(format!(
"sys.setrecursionlimit: cannot raise above current limit {current} (sandbox only allows lowering)"
))),
}
}