use super::{setting::Settings, thread, Context, VirtualMachine};
use crate::{stdlib::atexit, vm::PyBaseExceptionRef, PyResult};
use std::sync::atomic::Ordering;
pub struct Interpreter {
vm: VirtualMachine,
}
impl Interpreter {
pub fn without_stdlib(settings: Settings) -> Self {
Self::with_init(settings, |_| {})
}
pub fn with_init<F>(settings: Settings, init: F) -> Self
where
F: FnOnce(&mut VirtualMachine),
{
let ctx = Context::genesis();
crate::types::TypeZoo::extend(ctx);
crate::exceptions::ExceptionZoo::extend(ctx);
let mut vm = VirtualMachine::new(settings, ctx.clone());
init(&mut vm);
vm.initialize();
Self { vm }
}
pub fn enter<F, R>(&self, f: F) -> R
where
F: FnOnce(&VirtualMachine) -> R,
{
thread::enter_vm(&self.vm, || f(&self.vm))
}
pub fn enter_and_expect<F, R>(&self, f: F, msg: &str) -> R
where
F: FnOnce(&VirtualMachine) -> PyResult<R>,
{
self.enter(|vm| {
let result = f(vm);
vm.expect_pyresult(result, msg)
})
}
pub fn run<F>(self, f: F) -> u8
where
F: FnOnce(&VirtualMachine) -> PyResult<()>,
{
let res = self.enter(|vm| f(vm));
self.finalize(res.err())
}
pub fn finalize(self, exc: Option<PyBaseExceptionRef>) -> u8 {
self.enter(|vm| {
vm.flush_std();
let exit_code = if let Some(exc) = exc {
vm.handle_exit_exception(exc)
} else {
0
};
atexit::_run_exitfuncs(vm);
vm.state.finalizing.store(true, Ordering::Release);
vm.flush_std();
exit_code
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
builtins::{int, PyStr},
PyObjectRef,
};
use malachite_bigint::ToBigInt;
#[test]
fn test_add_py_integers() {
Interpreter::without_stdlib(Default::default()).enter(|vm| {
let a: PyObjectRef = vm.ctx.new_int(33_i32).into();
let b: PyObjectRef = vm.ctx.new_int(12_i32).into();
let res = vm._add(&a, &b).unwrap();
let value = int::get_value(&res);
assert_eq!(*value, 45_i32.to_bigint().unwrap());
})
}
#[test]
fn test_multiply_str() {
Interpreter::without_stdlib(Default::default()).enter(|vm| {
let a = vm.new_pyobj(crate::common::ascii!("Hello "));
let b = vm.new_pyobj(4_i32);
let res = vm._mul(&a, &b).unwrap();
let value = res.payload::<PyStr>().unwrap();
assert_eq!(value.as_ref(), "Hello Hello Hello Hello ")
})
}
}