use core::marker::PhantomData;
use crate::ser_de::SerDictFixed;
use crate::ser_de::SerWord;
use crate::Runtime;
use crate::RuntimeWord;
use crate::StepResult;
use crate::VerbSeqInner;
use crate::WhichToken;
use crate::{Error, ExecutionStack, Stack};
use heapless::{String, Vec};
#[derive(Debug)]
pub struct HVecStack<T, const N: usize> {
data: Vec<T, N>,
err: Error,
}
impl<T, const N: usize> HVecStack<T, N> {
pub fn new(err: Error) -> Self {
HVecStack {
data: Vec::new(),
err,
}
}
}
impl<T, const N: usize> Stack for HVecStack<T, N> {
type Item = T;
fn push(&mut self, data: T) -> Result<(), Error> {
self.data.push(data).map_err(|_| Error::StackOverflow).map(drop)
}
fn pop(&mut self) -> Result<T, Error> {
self.data.pop().ok_or(Error::DataStackUnderflow)
}
fn peek_back(&self, back: usize) -> Result<&Self::Item, Error> {
self.data.iter().rev().skip(back).next().ok_or(Error::DataStackUnderflow)
}
fn last(&self) -> Result<&Self::Item, Error> {
self.data.last().ok_or(Error::InternalError) }
fn pop_back(&mut self, back: usize) -> Result<Self::Item, Error> {
if back + 1 > self.data.len() {
return Err(Error::DataStackUnderflow);
}
let len = self.data.len();
let idx = len - back - 1;
unsafe {
let ret;
{
let ptr = self.data.as_mut_ptr().add(idx);
ret = core::ptr::read(ptr);
core::ptr::copy(ptr.offset(1), ptr, len - idx - 1);
}
self.data.set_len(len - 1);
Ok(ret)
}
}
}
impl<BuiltinTok, SeqTok, const N: usize> ExecutionStack<BuiltinTok, SeqTok>
for HVecStack<RuntimeWord<BuiltinTok, SeqTok>, N>
where
SeqTok: Clone,
BuiltinTok: Clone,
{
fn push(&mut self, data: RuntimeWord<BuiltinTok, SeqTok>) {
self.data.push(data).map_err(drop).unwrap()
}
fn pop(&mut self) -> Result<RuntimeWord<BuiltinTok, SeqTok>, Error> {
self.data.pop().ok_or(Error::FlowStackEmpty)
}
fn last_mut(&mut self) -> Result<&mut RuntimeWord<BuiltinTok, SeqTok>, Error> {
self.data.last_mut().ok_or(Error::FlowStackEmpty)
}
}
#[derive(Clone)]
pub struct BuiltinToken<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> {
bi: Builtin<DATA_SZ, FLOW_SZ, OUTBUF_SZ>,
}
impl<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize>
BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>
{
pub fn new(bi: Builtin<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Self {
Self { bi }
}
pub fn exec(&self, rt: &mut NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Result<(), Error> {
(self.bi)(rt)
}
}
pub type NoStdRuntime<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> = Runtime<
BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>,
usize,
HVecStack<i32, DATA_SZ>,
HVecStack<RuntimeWord<BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, usize>, FLOW_SZ>,
String<OUTBUF_SZ>,
>;
pub struct NoStdContext<
const DATA_SZ: usize,
const FLOW_SZ: usize,
const OUTBUF_SZ: usize,
const SEQS_CT: usize,
const SEQ_SZ: usize,
> {
pub rt: NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>,
pub seq:
Vec<Vec<RuntimeWord<BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, usize>, SEQ_SZ>, SEQS_CT>,
}
impl<
const DATA_SZ: usize,
const FLOW_SZ: usize,
const OUTBUF_SZ: usize,
const SEQS_CT: usize,
const SEQ_SZ: usize,
> NoStdContext<DATA_SZ, FLOW_SZ, OUTBUF_SZ, SEQS_CT, SEQ_SZ>
{
pub fn from_ser_dict<'a, const BIS_CT: usize>(
dict: &SerDictFixed<'a, SEQS_CT, SEQ_SZ, BIS_CT>,
) -> Self {
let rt = new_runtime();
let mut bis: Vec<Builtin<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, BIS_CT> = Vec::new();
for bi in dict.bis.iter() {
let func = nostd_builtins::<DATA_SZ, FLOW_SZ, OUTBUF_SZ>()
.iter()
.find(|(k, _v)| k == bi)
.map(|(_k, v)| v)
.unwrap();
bis.push(*func).ok();
}
let mut seqs_vec = Vec::new();
for seq in dict.data.iter() {
let mut seq_vec = Vec::new();
for seqstp in seq.iter() {
let proc = match seqstp {
SerWord::LiteralVal(lit) => RuntimeWord::LiteralVal(*lit),
SerWord::Verb(idx) => RuntimeWord::Verb(BuiltinToken {
bi: bis[*idx as usize],
}),
SerWord::VerbSeq(idx) => RuntimeWord::VerbSeq(VerbSeqInner {
tok: *idx as usize,
idx: 0,
}),
SerWord::UncondRelativeJump { offset } => {
RuntimeWord::UncondRelativeJump { offset: *offset }
}
SerWord::CondRelativeJump { offset, jump_on } => {
RuntimeWord::CondRelativeJump {
offset: *offset,
jump_on: *jump_on,
}
}
};
seq_vec.push(proc).ok();
}
seqs_vec.push(seq_vec).ok();
}
Self { rt, seq: seqs_vec }
}
pub fn run_blocking(&mut self) -> Result<(), Error> {
loop {
match self.rt.step() {
Ok(StepResult::Working(WhichToken::Single(ft))) => {
ft.exec(&mut self.rt).unwrap();
}
Ok(StepResult::Working(WhichToken::Ref(rtw))) => {
let c = self
.seq
.get(rtw.tok)
.and_then(|n| n.get(rtw.idx))
.map(|n| n.clone());
self.rt.provide_seq_tok(c).unwrap();
}
Ok(StepResult::Done) => break,
Err(e) => {
return Err(e);
}
}
}
Ok(())
}
}
pub type NoStdRuntimeWord<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> =
RuntimeWord<BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, usize>;
pub type Builtin<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> =
fn(&mut NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Result<(), Error>;
pub fn new_runtime<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize>(
) -> NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ> {
let ds = HVecStack::new(Error::DataStackEmpty);
let rs = HVecStack::new(Error::RetStackEmpty);
let fs = HVecStack::new(Error::FlowStackEmpty);
Runtime {
data_stk: ds,
ret_stk: rs,
flow_stk: fs,
_pd_ty_t_f: PhantomData,
cur_output: String::new(),
}
}
pub fn nostd_builtins<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize>(
) -> &'static [(
&'static str,
fn(&mut NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Result<(), Error>,
)] {
&[
("+", crate::builtins::bi_add),
(".", crate::builtins::bi_pop),
("2dup", crate::builtins::bi_2dup),
("<", crate::builtins::bi_lt),
("=", crate::builtins::bi_eq),
(">", crate::builtins::bi_gt),
(">r", crate::builtins::bi_retstk_push),
("cr", crate::builtins::bi_cr),
("drop", crate::builtins::bi_drop),
("dup", crate::builtins::bi_dup),
("emit", crate::builtins::bi_emit),
("pick", crate::builtins::bi_pick),
("PRIV_LOOP", crate::builtins::bi_priv_loop),
("r>", crate::builtins::bi_retstk_pop),
("roll", crate::builtins::bi_roll),
("rot", crate::builtins::bi_rot),
("swap", crate::builtins::bi_swap),
]
}