a4_core/
std_rt.rs

1use std::convert::TryInto;
2use std::marker::PhantomData;
3use std::sync::Arc;
4
5use crate::ser_de::SerWord;
6use crate::Runtime;
7use crate::RuntimeWord;
8use crate::{Error, ExecutionStack, Stack};
9
10#[derive(Debug)]
11pub struct StdVecStack<T> {
12    data: Vec<T>,
13    err: Error,
14}
15
16impl<T> StdVecStack<T> {
17    pub fn new(err: Error) -> Self {
18        StdVecStack {
19            data: Vec::new(),
20            err,
21        }
22    }
23}
24
25impl<T> StdVecStack<T> {
26    pub fn data(&self) -> &[T] {
27        &self.data
28    }
29}
30
31impl<T> Stack for StdVecStack<T> {
32    type Item = T;
33
34    fn push(&mut self, data: T) -> Result<(), Error> {
35        self.data.push(data);
36        Ok(())
37    }
38
39    fn pop(&mut self) -> Result<T, Error> {
40        self.data.pop().ok_or(Error::DataStackUnderflow)
41    }
42
43    fn peek_back(&self, back: usize) -> Result<&Self::Item, Error> {
44        self.data.iter().rev().skip(back).next().ok_or(Error::DataStackUnderflow)
45    }
46
47    fn last(&self) -> Result<&Self::Item, Error> {
48        self.data.last().ok_or(Error::InternalError) // TODO: Wrong error!
49    }
50
51    fn pop_back(&mut self, back: usize) -> Result<Self::Item, Error> {
52        if back + 1 > self.data.len() {
53            return Err(Error::DataStackUnderflow);
54        }
55        Ok(self.data.remove(self.data.len() - back - 1))
56    }
57}
58
59impl<T, F> ExecutionStack<T, F> for StdVecStack<RuntimeWord<T, F>>
60where
61    F: Clone,
62    T: Clone,
63{
64    fn push(&mut self, data: RuntimeWord<T, F>) {
65        self.data.push(data)
66    }
67    fn pop(&mut self) -> Result<RuntimeWord<T, F>, Error> {
68        self.data.pop().ok_or(Error::FlowStackEmpty)
69    }
70    fn last_mut(&mut self) -> Result<&mut RuntimeWord<T, F>, Error> {
71        self.data.last_mut().ok_or(Error::FlowStackEmpty)
72    }
73}
74
75#[derive(Clone)]
76pub struct BuiltinToken {
77    bi: Builtin,
78}
79
80impl BuiltinToken {
81    pub fn new(bi: Builtin) -> Self {
82        Self { bi }
83    }
84
85    pub fn exec(&self, rt: &mut StdRuntime) -> Result<(), Error> {
86        (self.bi)(rt)
87    }
88}
89
90pub type StdRuntime = Runtime<
91    BuiltinToken,
92    String,
93    StdVecStack<i32>,
94    StdVecStack<RuntimeWord<BuiltinToken, String>>,
95    String,
96>;
97
98#[derive(Clone)]
99pub struct NamedStdRuntimeWord {
100    pub name: String,
101    pub word: RuntimeWord<BuiltinToken, String>,
102}
103
104#[derive(Clone)]
105pub struct StdFuncSeq {
106    pub inner: Arc<Vec<NamedStdRuntimeWord>>,
107}
108
109pub type StdRuntimeWord = RuntimeWord<BuiltinToken, String>;
110
111type Builtin = fn(&mut StdRuntime) -> Result<(), Error>;
112
113pub fn new_runtime() -> StdRuntime {
114    // These are the only data structures required, and Runtime is generic over the
115    // stacks, so I could easily use heapless::Vec as a backing structure as well
116    let ds = StdVecStack::new(Error::DataStackEmpty);
117    let rs = StdVecStack::new(Error::RetStackEmpty);
118    let fs = StdVecStack::new(Error::FlowStackEmpty);
119
120    // This is a generic Runtime type, I'll likely define two versions:
121    // One with std-ability (for the host), and one no-std one, so users
122    // wont have to deal with all the generic shenanigans
123    Runtime {
124        data_stk: ds,
125        ret_stk: rs,
126        flow_stk: fs,
127        _pd_ty_t_f: PhantomData,
128        cur_output: String::new(),
129    }
130}
131
132pub fn std_builtins() -> &'static [(&'static str, fn(&mut StdRuntime) -> Result<(), Error>)] {
133    &[
134        ("+", crate::builtins::bi_add),
135        (".", crate::builtins::bi_pop),
136        ("2dup", crate::builtins::bi_2dup),
137        ("<", crate::builtins::bi_lt),
138        ("=", crate::builtins::bi_eq),
139        (">", crate::builtins::bi_gt),
140        (">r", crate::builtins::bi_retstk_push),
141        ("cr", crate::builtins::bi_cr),
142        ("drop", crate::builtins::bi_drop),
143        ("dup", crate::builtins::bi_dup),
144        ("emit", crate::builtins::bi_emit),
145        ("pick", crate::builtins::bi_pick),
146        ("PRIV_LOOP", crate::builtins::bi_priv_loop),
147        ("r>", crate::builtins::bi_retstk_pop),
148        ("roll", crate::builtins::bi_roll),
149        ("rot", crate::builtins::bi_rot),
150        ("swap", crate::builtins::bi_swap),
151    ]
152}
153
154pub struct SerContext {
155    pub bis: Vec<String>,
156    pub seqs: Vec<String>,
157}
158
159impl SerContext {
160    pub fn new() -> Self {
161        Self {
162            bis: Vec::new(),
163            seqs: Vec::new(),
164        }
165    }
166
167    pub fn encode_rtw(&mut self, word: &NamedStdRuntimeWord) -> SerWord {
168        match &word.word {
169            RuntimeWord::LiteralVal(lit) => SerWord::LiteralVal(*lit),
170            RuntimeWord::Verb(_) => {
171                let idx = self.intern_bis(&word.name);
172                SerWord::Verb(idx)
173            }
174            RuntimeWord::VerbSeq(seq) => {
175                let idx = self.intern_seq(&seq.tok);
176                SerWord::VerbSeq(idx)
177            }
178            RuntimeWord::UncondRelativeJump { offset } => {
179                SerWord::UncondRelativeJump { offset: *offset }
180            }
181            RuntimeWord::CondRelativeJump { offset, jump_on } => SerWord::CondRelativeJump {
182                offset: *offset,
183                jump_on: *jump_on,
184            },
185        }
186    }
187
188    pub fn intern_bis(&mut self, word: &str) -> u16 {
189        if let Some(pos) = self.bis.iter().position(|w| word == w) {
190            pos
191        } else {
192            self.bis.push(word.to_string());
193            self.bis.len() - 1
194        }
195        .try_into()
196        .unwrap()
197    }
198
199    pub fn intern_seq(&mut self, word: &str) -> u16 {
200        if let Some(pos) = self.seqs.iter().position(|w| word == w) {
201            pos
202        } else {
203            self.seqs.push(word.to_string());
204            self.seqs.len() - 1
205        }
206        .try_into()
207        .unwrap()
208    }
209}
210
211// TODO: Make a method of NamedStdRuntimeWord
212pub fn ser_srw(ctxt: &mut SerContext, name: &str, words: &StdFuncSeq) -> Vec<SerWord> {
213    let mut out = vec![];
214
215    for word in words.inner.iter() {
216        let new = ctxt.encode_rtw(word);
217        out.push(new);
218    }
219
220    // Ensure that the currently encoded word makes it into
221    // the list of interned words
222    let _ = ctxt.intern_seq(name);
223
224    out
225}