use crate::data::{Data, Mem};
use crate::error::{KernelError, Severity};
use crate::host::{Io, NullHost};
use crate::state::{Booted, Booting, State};
use crate::vm::{Stop, Vm};
use crate::{Error, FALSE, Result, TRUE};
mod boot;
mod builtins;
mod context;
pub(crate) mod dict;
mod env;
mod layout;
use context::Context;
use dict::Dict;
use env::Environment;
use layout::{INPUT_BUFFER_SIZE, Layout};
pub use env::Config;
const MAX_WORD_LEN: usize = 31;
const MAX_BUILTINS: usize = 256;
pub(crate) const MIN_DATA_SPACE: usize = 2 << 15;
pub(crate) type Builtin<M, H> = fn(&mut H, &mut Context<'_, M>) -> Result<()>;
pub struct Kernel<M: Mem = [u8; 65536], H: Io = NullHost, S: State = Booting> {
vm: Vm,
data: Data<M>,
host: H,
builtins: [Option<Builtin<M, H>>; MAX_BUILTINS],
builtins_len: usize,
layout_base: usize,
env: Environment,
state: S,
}
impl<M: Mem, H: Io, S: State> Kernel<M, H, S> {
pub fn push(&mut self, x: usize) -> Result<()> {
self.vm.push(&mut self.data, x)?;
Ok(())
}
pub fn pop(&mut self) -> Result<usize> {
Ok(self.vm.pop(&mut self.data)?)
}
pub fn reset(&mut self) {
self.vm.reset()
}
pub fn stack(&self) -> impl Iterator<Item = usize> + '_ {
self.vm.stack(&self.data)
}
pub(crate) fn dict(&mut self) -> Dict<'_, M> {
Dict::new(&mut self.data, self.layout_base)
}
pub(super) fn execute(&mut self, xt: usize) -> Result<()> {
let mut stop = match self.vm.enter(&mut self.data, xt) {
Ok(s) => s,
Err(e) => self.throw(e.into())?,
};
loop {
match stop {
Stop::Halt => return Ok(()),
Stop::Yield(token) => {
let f = self.builtins[token.index]
.ok_or(KernelError::InvalidBuiltin(token.index as u8))?;
let host = &mut self.host;
let mut ctx = Context::new(&mut self.vm, &mut self.data, self.layout_base);
stop = match f(host, &mut ctx) {
Ok(()) => match self.vm.resume(&mut self.data, token) {
Ok(s) => s,
Err(e) => self.throw(e.into())?,
},
Err(e) => self.throw(e)?,
};
}
}
}
}
fn throw(&mut self, e: Error) -> Result<Stop> {
let ior = match e.severity() {
Severity::Throw(ior) => ior,
Severity::Abort => return Err(self.abort(e)),
};
match self.state.throw_xt() {
Some(throw_xt) => {
self.push(ior.into())?;
match self.vm.enter(&mut self.data, throw_xt.into()) {
Ok(stop) => Ok(stop),
Err(e) => Err(self.abort(e.into())),
}
}
None => Err(Error::Throw(ior)),
}
}
fn abort(&mut self, e: Error) -> Error {
let state_addr = self.dict().addr(Layout::STATE);
let _ = self.data.write_cell(state_addr, FALSE);
self.vm.reset();
e
}
pub(super) fn set_source(&mut self, code: &[u8]) -> Result<()> {
self.dict().set_source(code)
}
}
impl<M: Mem, H: Io> Kernel<M, H, Booted> {
pub(super) fn catch_interpret(&mut self) -> Result<()> {
self.push(self.state.xt_interpret)?;
self.execute(self.state.xt_catch)?;
let code = self.pop()? as isize;
if code != 0 {
return Err(Error::Throw(code.into()));
}
Ok(())
}
}