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}