anachro_forth_core/
nostd_rt.rs

1use core::marker::PhantomData;
2
3use crate::ser_de::SerDictFixed;
4use crate::ser_de::SerWord;
5use crate::Runtime;
6use crate::RuntimeWord;
7use crate::StepResult;
8use crate::VerbSeqInner;
9use crate::WhichToken;
10use crate::{Error, ExecutionStack, Stack};
11
12use heapless::{String, Vec};
13
14#[derive(Debug)]
15pub struct HVecStack<T, const N: usize> {
16    data: Vec<T, N>,
17    err: Error,
18}
19
20impl<T, const N: usize> HVecStack<T, N> {
21    pub fn new(err: Error) -> Self {
22        HVecStack {
23            data: Vec::new(),
24            err,
25        }
26    }
27}
28
29impl<T, const N: usize> Stack for HVecStack<T, N> {
30    type Item = T;
31
32    fn push(&mut self, data: T) {
33        self.data.push(data).map_err(drop).unwrap();
34    }
35
36    fn pop(&mut self) -> Result<T, Error> {
37        self.data.pop().ok_or(Error::DataStackUnderflow)
38    }
39
40    fn last(&self) -> Result<&Self::Item, Error> {
41        self.data.last().ok_or(Error::InternalError) // TODO: Wrong error!
42    }
43}
44
45impl<BuiltinTok, SeqTok, const N: usize> ExecutionStack<BuiltinTok, SeqTok>
46    for HVecStack<RuntimeWord<BuiltinTok, SeqTok>, N>
47where
48    SeqTok: Clone,
49    BuiltinTok: Clone,
50{
51    fn push(&mut self, data: RuntimeWord<BuiltinTok, SeqTok>) {
52        // TODO
53        self.data.push(data).map_err(drop).unwrap()
54    }
55    fn pop(&mut self) -> Result<RuntimeWord<BuiltinTok, SeqTok>, Error> {
56        self.data.pop().ok_or(Error::FlowStackEmpty)
57    }
58    fn last_mut(&mut self) -> Result<&mut RuntimeWord<BuiltinTok, SeqTok>, Error> {
59        self.data.last_mut().ok_or(Error::FlowStackEmpty)
60    }
61}
62
63#[derive(Clone)]
64pub struct BuiltinToken<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> {
65    bi: Builtin<DATA_SZ, FLOW_SZ, OUTBUF_SZ>,
66}
67
68impl<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize>
69    BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>
70{
71    pub fn new(bi: Builtin<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Self {
72        Self { bi }
73    }
74
75    pub fn exec(&self, rt: &mut NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Result<(), Error> {
76        (self.bi)(rt)
77    }
78}
79
80pub type NoStdRuntime<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> = Runtime<
81    BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>,
82    usize,
83    HVecStack<i32, DATA_SZ>,
84    HVecStack<RuntimeWord<BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, usize>, FLOW_SZ>,
85    String<OUTBUF_SZ>,
86>;
87
88pub struct NoStdContext<
89    const DATA_SZ: usize,
90    const FLOW_SZ: usize,
91    const OUTBUF_SZ: usize,
92    const SEQS_CT: usize,
93    const SEQ_SZ: usize,
94> {
95    pub rt: NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>,
96    pub seq:
97        Vec<Vec<RuntimeWord<BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, usize>, SEQ_SZ>, SEQS_CT>,
98}
99
100impl<
101        const DATA_SZ: usize,
102        const FLOW_SZ: usize,
103        const OUTBUF_SZ: usize,
104        const SEQS_CT: usize,
105        const SEQ_SZ: usize,
106    > NoStdContext<DATA_SZ, FLOW_SZ, OUTBUF_SZ, SEQS_CT, SEQ_SZ>
107{
108    pub fn from_ser_dict<'a, const BIS_CT: usize>(
109        dict: &SerDictFixed<'a, SEQS_CT, SEQ_SZ, BIS_CT>,
110    ) -> Self {
111        let rt = new_runtime();
112        let mut bis: Vec<Builtin<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, BIS_CT> = Vec::new();
113
114        // Fill in the builtin LUT
115        for bi in dict.bis.iter() {
116            let func = nostd_builtins::<DATA_SZ, FLOW_SZ, OUTBUF_SZ>()
117                .iter()
118                .find(|(k, _v)| k == bi)
119                .map(|(_k, v)| v)
120                .unwrap();
121
122            bis.push(*func).ok();
123        }
124
125        let mut seqs_vec = Vec::new();
126
127        for seq in dict.data.iter() {
128            let mut seq_vec = Vec::new();
129
130            for seqstp in seq.iter() {
131                let proc = match seqstp {
132                    SerWord::LiteralVal(lit) => RuntimeWord::LiteralVal(*lit),
133                    SerWord::Verb(idx) => RuntimeWord::Verb(BuiltinToken {
134                        bi: bis[*idx as usize],
135                    }),
136                    SerWord::VerbSeq(idx) => RuntimeWord::VerbSeq(VerbSeqInner {
137                        tok: *idx as usize,
138                        idx: 0,
139                    }),
140                    SerWord::UncondRelativeJump { offset } => {
141                        RuntimeWord::UncondRelativeJump { offset: *offset }
142                    }
143                    SerWord::CondRelativeJump { offset, jump_on } => {
144                        RuntimeWord::CondRelativeJump {
145                            offset: *offset,
146                            jump_on: *jump_on,
147                        }
148                    }
149                };
150                seq_vec.push(proc).ok();
151            }
152
153            seqs_vec.push(seq_vec).ok();
154        }
155
156        Self { rt, seq: seqs_vec }
157    }
158
159    pub fn run_blocking(&mut self) -> Result<(), Error> {
160        loop {
161            match self.rt.step() {
162                Ok(StepResult::Working(WhichToken::Single(ft))) => {
163                    // The runtime yields back at every call to a "builtin". Here, I
164                    // call the builtin immediately, but I could also yield further up,
165                    // to be resumed at a later time
166                    ft.exec(&mut self.rt).unwrap();
167                }
168                Ok(StepResult::Working(WhichToken::Ref(rtw))) => {
169                    // The runtime yields back at every call to a "builtin". Here, I
170                    // call the builtin immediately, but I could also yield further up,
171                    // to be resumed at a later time
172
173                    let c = self
174                        .seq
175                        .get(rtw.tok)
176                        .and_then(|n| n.get(rtw.idx))
177                        .map(|n| n.clone());
178
179                    self.rt.provide_seq_tok(c).unwrap();
180                }
181                Ok(StepResult::Done) => break,
182                Err(e) => {
183                    // eprintln!("ERROR! -> {:?}", e);
184                    return Err(e);
185                }
186            }
187        }
188        Ok(())
189    }
190}
191
192pub type NoStdRuntimeWord<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> =
193    RuntimeWord<BuiltinToken<DATA_SZ, FLOW_SZ, OUTBUF_SZ>, usize>;
194
195pub type Builtin<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize> =
196    fn(&mut NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Result<(), Error>;
197
198pub fn new_runtime<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize>(
199) -> NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ> {
200    // These are the only data structures required, and Runtime is generic over the
201    // stacks, so I could easily use heapless::Vec as a backing structure as well
202    let ds = HVecStack::new(Error::DataStackEmpty);
203    let rs = HVecStack::new(Error::RetStackEmpty);
204    let fs = HVecStack::new(Error::FlowStackEmpty);
205
206    // This is a generic Runtime type, I'll likely define two versions:
207    // One with std-ability (for the host), and one no-std one, so users
208    // wont have to deal with all the generic shenanigans
209    Runtime {
210        data_stk: ds,
211        ret_stk: rs,
212        flow_stk: fs,
213        _pd_ty_t_f: PhantomData,
214        cur_output: String::new(),
215    }
216}
217
218pub fn nostd_builtins<const DATA_SZ: usize, const FLOW_SZ: usize, const OUTBUF_SZ: usize>(
219) -> &'static [(
220    &'static str,
221    fn(&mut NoStdRuntime<DATA_SZ, FLOW_SZ, OUTBUF_SZ>) -> Result<(), Error>,
222)] {
223    &[
224        ("emit", crate::builtins::bi_emit),
225        (".", crate::builtins::bi_pop),
226        ("cr", crate::builtins::bi_cr),
227        (">r", crate::builtins::bi_retstk_push),
228        ("r>", crate::builtins::bi_retstk_pop),
229        ("=", crate::builtins::bi_eq),
230        ("<", crate::builtins::bi_lt),
231        (">", crate::builtins::bi_gt),
232        ("dup", crate::builtins::bi_dup),
233        ("+", crate::builtins::bi_add),
234        ("PRIV_LOOP", crate::builtins::bi_priv_loop),
235    ]
236}