use core::marker::PhantomData;
use crate::core::{Core, CoreConfig, CoreExt, Status};
use crate::isa::{Instr, Instruction};
use crate::library::{Jump, Lib, LibId, LibSite};
#[derive(Clone, Debug, Default)]
pub struct Vm<Isa = Instr<LibId>>
where Isa: Instruction<LibId>
{
pub core: Core<LibId, Isa::Core>,
phantom: PhantomData<Isa>,
}
impl<Isa> Vm<Isa>
where Isa: Instruction<LibId>
{
pub fn new() -> Self { Self { core: Core::new(), phantom: Default::default() } }
pub fn with(config: CoreConfig, cx_config: <Isa::Core as CoreExt>::Config) -> Self {
Self {
core: Core::with(config, cx_config),
phantom: Default::default(),
}
}
pub fn reset(&mut self) { self.core.reset(); }
pub fn exec<L: AsRef<Lib>>(
&mut self,
entry_point: LibSite,
context: &Isa::Context<'_>,
lib_resolver: impl Fn(LibId) -> Option<L>,
) -> Status {
let mut site = entry_point;
let mut skip = false;
loop {
if let Some(lib) = lib_resolver(site.lib_id) {
let jump = lib
.as_ref()
.exec::<Isa>(site.offset, skip, &mut self.core, context);
match jump {
Jump::Halt => {
#[cfg(feature = "log")]
{
let core = &self.core;
let z = "\x1B[0m";
let y = "\x1B[0;33m";
let c = if core.ck().is_ok() { "\x1B[0;32m" } else { "\x1B[0;31m" };
eprintln!();
eprintln!(
">; execution stopped: {y}CK{z} {c}{}{z}, {y}CO{z} {c}{}{z}",
core.ck(),
core.co()
);
}
break;
}
Jump::Instr(new_site) => {
skip = false;
site = new_site.into();
}
Jump::Next(new_site) => {
skip = true;
site = new_site.into();
}
}
} else {
let fail = self.core.fail_ck();
if fail {
break;
} else if let Some(pos) = site.offset.checked_add(1) {
site.offset = pos;
} else {
break;
}
};
}
self.core.ck()
}
}