use std::convert::TryInto;
use std::marker::PhantomData;
use std::sync::Arc;
use crate::ser_de::SerWord;
use crate::Runtime;
use crate::RuntimeWord;
use crate::{Error, ExecutionStack, Stack};
#[derive(Debug)]
pub struct StdVecStack<T> {
data: Vec<T>,
err: Error,
}
impl<T> StdVecStack<T> {
pub fn new(err: Error) -> Self {
StdVecStack {
data: Vec::new(),
err,
}
}
}
impl<T> StdVecStack<T> {
pub fn data(&self) -> &[T] {
&self.data
}
}
impl<T> Stack for StdVecStack<T> {
type Item = T;
fn push(&mut self, data: T) -> Result<(), Error> {
self.data.push(data);
Ok(())
}
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);
}
Ok(self.data.remove(self.data.len() - back - 1))
}
}
impl<T, F> ExecutionStack<T, F> for StdVecStack<RuntimeWord<T, F>>
where
F: Clone,
T: Clone,
{
fn push(&mut self, data: RuntimeWord<T, F>) {
self.data.push(data)
}
fn pop(&mut self) -> Result<RuntimeWord<T, F>, Error> {
self.data.pop().ok_or(Error::FlowStackEmpty)
}
fn last_mut(&mut self) -> Result<&mut RuntimeWord<T, F>, Error> {
self.data.last_mut().ok_or(Error::FlowStackEmpty)
}
}
#[derive(Clone)]
pub struct BuiltinToken {
bi: Builtin,
}
impl BuiltinToken {
pub fn new(bi: Builtin) -> Self {
Self { bi }
}
pub fn exec(&self, rt: &mut StdRuntime) -> Result<(), Error> {
(self.bi)(rt)
}
}
pub type StdRuntime = Runtime<
BuiltinToken,
String,
StdVecStack<i32>,
StdVecStack<RuntimeWord<BuiltinToken, String>>,
String,
>;
#[derive(Clone)]
pub struct NamedStdRuntimeWord {
pub name: String,
pub word: RuntimeWord<BuiltinToken, String>,
}
#[derive(Clone)]
pub struct StdFuncSeq {
pub inner: Arc<Vec<NamedStdRuntimeWord>>,
}
pub type StdRuntimeWord = RuntimeWord<BuiltinToken, String>;
type Builtin = fn(&mut StdRuntime) -> Result<(), Error>;
pub fn new_runtime() -> StdRuntime {
let ds = StdVecStack::new(Error::DataStackEmpty);
let rs = StdVecStack::new(Error::RetStackEmpty);
let fs = StdVecStack::new(Error::FlowStackEmpty);
Runtime {
data_stk: ds,
ret_stk: rs,
flow_stk: fs,
_pd_ty_t_f: PhantomData,
cur_output: String::new(),
}
}
pub fn std_builtins() -> &'static [(&'static str, fn(&mut StdRuntime) -> 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),
]
}
pub struct SerContext {
pub bis: Vec<String>,
pub seqs: Vec<String>,
}
impl SerContext {
pub fn new() -> Self {
Self {
bis: Vec::new(),
seqs: Vec::new(),
}
}
pub fn encode_rtw(&mut self, word: &NamedStdRuntimeWord) -> SerWord {
match &word.word {
RuntimeWord::LiteralVal(lit) => SerWord::LiteralVal(*lit),
RuntimeWord::Verb(_) => {
let idx = self.intern_bis(&word.name);
SerWord::Verb(idx)
}
RuntimeWord::VerbSeq(seq) => {
let idx = self.intern_seq(&seq.tok);
SerWord::VerbSeq(idx)
}
RuntimeWord::UncondRelativeJump { offset } => {
SerWord::UncondRelativeJump { offset: *offset }
}
RuntimeWord::CondRelativeJump { offset, jump_on } => SerWord::CondRelativeJump {
offset: *offset,
jump_on: *jump_on,
},
}
}
pub fn intern_bis(&mut self, word: &str) -> u16 {
if let Some(pos) = self.bis.iter().position(|w| word == w) {
pos
} else {
self.bis.push(word.to_string());
self.bis.len() - 1
}
.try_into()
.unwrap()
}
pub fn intern_seq(&mut self, word: &str) -> u16 {
if let Some(pos) = self.seqs.iter().position(|w| word == w) {
pos
} else {
self.seqs.push(word.to_string());
self.seqs.len() - 1
}
.try_into()
.unwrap()
}
}
pub fn ser_srw(ctxt: &mut SerContext, name: &str, words: &StdFuncSeq) -> Vec<SerWord> {
let mut out = vec![];
for word in words.inner.iter() {
let new = ctxt.encode_rtw(word);
out.push(new);
}
let _ = ctxt.intern_seq(name);
out
}