use crate::{
error::{EvalResult, InterpreterError},
value::{ExceptionValue, Value},
};
pub const STDOUT_SENTINEL: &str = "sys.stdout";
pub const STDERR_SENTINEL: &str = "sys.stderr";
pub fn constant(name: &str) -> Option<Value> {
match name {
"stdout" => Some(Value::Type(STDOUT_SENTINEL.to_string())),
"stderr" => Some(Value::Type(STDERR_SENTINEL.to_string())),
"stdin" => Some(Value::Type("sys.stdin".to_string())),
"maxsize" => Some(Value::Int(i64::MAX)),
"byteorder" => Some(Value::String("little".into())),
_ => None,
}
}
pub fn has_function(name: &str) -> bool {
matches!(name, "exit")
}
pub fn call(func: &str, args: &[Value]) -> EvalResult {
match func {
"exit" => {
let code = args.first().cloned().unwrap_or(Value::None);
let message = match &code {
Value::None => String::new(),
Value::Int(n) => n.to_string(),
other => format!("{other}"),
};
let mut exc = ExceptionValue::new("SystemExit", message);
exc.args = vec![code];
Err(crate::error::EvalError::Exception(exc))
}
_ => {
Err(InterpreterError::AttributeError(format!("module 'sys' has no attribute '{func}'"))
.into())
}
}
}
pub struct SysModule;
#[async_trait::async_trait]
impl crate::eval::modules::Module for SysModule {
fn name(&self) -> &'static str {
"sys"
}
fn constant(&self, name: &str) -> Option<Value> {
constant(name)
}
fn has_function(&self, name: &str) -> bool {
has_function(name)
}
async fn call(
&self,
_state: &mut crate::state::InterpreterState,
func: &str,
args: &[Value],
_kwargs: &indexmap::IndexMap<String, Value>,
_tools: &crate::tools::Tools,
) -> EvalResult {
call(func, args)
}
}