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