a4_core/
builtins.rs

1use crate::*;
2use core::fmt::Write;
3
4pub fn bi_emit<BuiltinTok, SeqTok, Sdata, Sexec, O>(
5    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
6) -> Result<(), Error>
7where
8    Sdata: Stack<Item = i32>,
9    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
10    SeqTok: Clone,
11    BuiltinTok: Clone,
12    O: Write,
13{
14    let word = ctxt.data_stk.pop()? as u32;
15    let symbol = core::char::from_u32(word).unwrap_or('‽');
16    write!(&mut ctxt.cur_output, "{}", symbol).map_err(|_| Error::OutputFormat)
17}
18
19pub fn bi_pop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
20    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
21) -> Result<(), Error>
22where
23    Sdata: Stack<Item = i32>,
24    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
25    SeqTok: Clone,
26    BuiltinTok: Clone,
27    O: Write,
28{
29    writeln!(&mut ctxt.cur_output, "{}", ctxt.data_stk.pop()?)?;
30    Ok(())
31}
32
33pub fn bi_drop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
34    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
35) -> Result<(), Error>
36where
37    Sdata: Stack<Item = i32>,
38    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
39    SeqTok: Clone,
40    BuiltinTok: Clone,
41    O: Write,
42{
43    let _ = ctxt.data_stk.pop()?;
44    Ok(())
45}
46
47pub fn bi_rot<BuiltinTok, SeqTok, Sdata, Sexec, O>(
48    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
49) -> Result<(), Error>
50where
51    Sdata: Stack<Item = i32>,
52    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
53    SeqTok: Clone,
54    BuiltinTok: Clone,
55    O: Write,
56{
57    let top = ctxt.data_stk.pop()?;
58    let mid = ctxt.data_stk.pop()?;
59    let bot = ctxt.data_stk.pop()?;
60
61    ctxt.data_stk.push(mid)?;
62    ctxt.data_stk.push(top)?;
63    ctxt.data_stk.push(bot)?;
64
65    Ok(())
66}
67
68pub fn bi_cr<BuiltinTok, SeqTok, Sdata, Sexec, O>(
69    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
70) -> Result<(), Error>
71where
72    Sdata: Stack<Item = i32>,
73    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
74    SeqTok: Clone,
75    BuiltinTok: Clone,
76    O: Write,
77{
78    writeln!(&mut ctxt.cur_output)?;
79    Ok(())
80}
81
82pub fn bi_lt<BuiltinTok, SeqTok, Sdata, Sexec, O>(
83    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
84) -> Result<(), Error>
85where
86    Sdata: Stack<Item = i32>,
87    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
88    SeqTok: Clone,
89    BuiltinTok: Clone,
90    O: Write,
91{
92    let val2 = ctxt.data_stk.pop()?;
93    let val1 = ctxt.data_stk.pop()?;
94    ctxt.data_stk.push(if val1 < val2 { -1 } else { 0 })?;
95    Ok(())
96}
97
98pub fn bi_gt<BuiltinTok, SeqTok, Sdata, Sexec, O>(
99    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
100) -> Result<(), Error>
101where
102    Sdata: Stack<Item = i32>,
103    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
104    SeqTok: Clone,
105    BuiltinTok: Clone,
106    O: Write,
107{
108    let val2 = ctxt.data_stk.pop()?;
109    let val1 = ctxt.data_stk.pop()?;
110    ctxt.data_stk.push(if val1 > val2 { -1 } else { 0 })?;
111    Ok(())
112}
113
114pub fn bi_retstk_push<BuiltinTok, SeqTok, Sdata, Sexec, O>(
115    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
116) -> Result<(), Error>
117where
118    Sdata: Stack<Item = i32>,
119    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
120    SeqTok: Clone,
121    BuiltinTok: Clone,
122    O: Write,
123{
124    let val = ctxt.data_stk.pop()?;
125    ctxt.ret_stk.push(val)?;
126    Ok(())
127}
128
129pub fn bi_retstk_pop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
130    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
131) -> Result<(), Error>
132where
133    Sdata: Stack<Item = i32>,
134    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
135    SeqTok: Clone,
136    BuiltinTok: Clone,
137    O: Write,
138{
139    let val = ctxt.ret_stk.pop()?;
140    ctxt.data_stk.push(val)?;
141    Ok(())
142}
143
144pub fn bi_eq<BuiltinTok, SeqTok, Sdata, Sexec, O>(
145    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
146) -> Result<(), Error>
147where
148    Sdata: Stack<Item = i32>,
149    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
150    SeqTok: Clone,
151    BuiltinTok: Clone,
152    O: Write,
153{
154    let val1 = ctxt.data_stk.pop()?;
155    let val2 = ctxt.data_stk.pop()?;
156    ctxt.data_stk.push(if val1 == val2 { -1 } else { 0 })?;
157    Ok(())
158}
159
160pub fn bi_add<BuiltinTok, SeqTok, Sdata, Sexec, O>(
161    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
162) -> Result<(), Error>
163where
164    Sdata: Stack<Item = i32>,
165    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
166    SeqTok: Clone,
167    BuiltinTok: Clone,
168    O: Write,
169{
170    let val1 = ctxt.data_stk.pop()?;
171    let val2 = ctxt.data_stk.pop()?;
172    ctxt.data_stk.push(val1.wrapping_add(val2))?;
173    Ok(())
174}
175
176pub fn bi_dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
177    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
178) -> Result<(), Error>
179where
180    Sdata: Stack<Item = i32>,
181    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
182    SeqTok: Clone,
183    BuiltinTok: Clone,
184    O: Write,
185{
186    let val1 = *ctxt.data_stk.last()?;
187    ctxt.data_stk.push(val1)?;
188    Ok(())
189}
190
191pub fn bi_retstk_dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
192    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
193) -> Result<(), Error>
194where
195    Sdata: Stack<Item = i32>,
196    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
197    SeqTok: Clone,
198    BuiltinTok: Clone,
199    O: Write,
200{
201    let val1 = *ctxt.ret_stk.last()?;
202    ctxt.ret_stk.push(val1)?;
203    Ok(())
204}
205
206pub fn bi_2dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
207    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
208) -> Result<(), Error>
209where
210    Sdata: Stack<Item = i32>,
211    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
212    SeqTok: Clone,
213    BuiltinTok: Clone,
214    O: Write,
215{
216    let val1 = ctxt.data_stk.pop()?;
217    let val2 = ctxt.data_stk.pop()?;
218    ctxt.data_stk.push(val2)?;
219    ctxt.data_stk.push(val1)?;
220    ctxt.data_stk.push(val2)?;
221    ctxt.data_stk.push(val1)?;
222    Ok(())
223}
224
225pub fn bi_retstk_swap<BuiltinTok, SeqTok, Sdata, Sexec, O>(
226    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
227) -> Result<(), Error>
228where
229    Sdata: Stack<Item = i32>,
230    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
231    SeqTok: Clone,
232    BuiltinTok: Clone,
233    O: Write,
234{
235    let top = ctxt.ret_stk.pop()?;
236    let bot = ctxt.ret_stk.pop()?;
237    ctxt.ret_stk.push(top)?;
238    ctxt.ret_stk.push(bot)?;
239
240    Ok(())
241}
242
243pub fn bi_swap<BuiltinTok, SeqTok, Sdata, Sexec, O>(
244    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
245) -> Result<(), Error>
246where
247    Sdata: Stack<Item = i32>,
248    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
249    SeqTok: Clone,
250    BuiltinTok: Clone,
251    O: Write,
252{
253    let top = ctxt.data_stk.pop()?;
254    let bot = ctxt.data_stk.pop()?;
255    ctxt.data_stk.push(top)?;
256    ctxt.data_stk.push(bot)?;
257
258    Ok(())
259}
260
261pub fn bi_pick<BuiltinTok, SeqTok, Sdata, Sexec, O>(
262    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
263) -> Result<(), Error>
264where
265    Sdata: Stack<Item = i32>,
266    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
267    SeqTok: Clone,
268    BuiltinTok: Clone,
269    O: Write,
270{
271    let top = ctxt.data_stk.pop()?;
272    let val = *ctxt.data_stk.peek_back(top.try_into().map_err(|_| Error::DataStackUnderflow)?)?;
273    ctxt.data_stk.push(val)?;
274
275    Ok(())
276}
277
278pub fn bi_roll<BuiltinTok, SeqTok, Sdata, Sexec, O>(
279    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
280) -> Result<(), Error>
281where
282    Sdata: Stack<Item = i32>,
283    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
284    SeqTok: Clone,
285    BuiltinTok: Clone,
286    O: Write,
287{
288    let top = ctxt.data_stk.pop()?;
289    let val = ctxt.data_stk.pop_back(top.try_into().map_err(|_| Error::DataStackUnderflow)?)?;
290    ctxt.data_stk.push(val)?;
291
292    Ok(())
293}
294
295pub fn bi_priv_loop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
296    ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
297) -> Result<(), Error>
298where
299    Sdata: Stack<Item = i32>,
300    Sexec: ExecutionStack<BuiltinTok, SeqTok>,
301    SeqTok: Clone,
302    BuiltinTok: Clone,
303    O: Write,
304{
305    let lmt = ctxt.ret_stk.pop()?;
306    let mut idx = ctxt.ret_stk.pop()?;
307
308    idx = idx.checked_add(1).ok_or(Error::BadMath)?;
309
310    if idx == lmt {
311        ctxt.data_stk.push(-1)?;
312    } else {
313        ctxt.data_stk.push(0)?;
314        ctxt.ret_stk.push(idx)?;
315        ctxt.ret_stk.push(lmt)?;
316    }
317
318    Ok(())
319}