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_cr<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 writeln!(&mut ctxt.cur_output)?;
44 Ok(())
45}
46
47pub fn bi_lt<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 val2 = ctxt.data_stk.pop()?;
58 let val1 = ctxt.data_stk.pop()?;
59 ctxt.data_stk.push(if val1 < val2 { -1 } else { 0 });
60 Ok(())
61}
62
63pub fn bi_gt<BuiltinTok, SeqTok, Sdata, Sexec, O>(
64 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
65) -> Result<(), Error>
66where
67 Sdata: Stack<Item = i32>,
68 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
69 SeqTok: Clone,
70 BuiltinTok: Clone,
71 O: Write,
72{
73 let val2 = ctxt.data_stk.pop()?;
74 let val1 = ctxt.data_stk.pop()?;
75 ctxt.data_stk.push(if val1 > val2 { -1 } else { 0 });
76 Ok(())
77}
78
79pub fn bi_retstk_push<BuiltinTok, SeqTok, Sdata, Sexec, O>(
80 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
81) -> Result<(), Error>
82where
83 Sdata: Stack<Item = i32>,
84 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
85 SeqTok: Clone,
86 BuiltinTok: Clone,
87 O: Write,
88{
89 let val = ctxt.data_stk.pop()?;
90 ctxt.ret_stk.push(val);
91 Ok(())
92}
93
94pub fn bi_retstk_pop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
95 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
96) -> Result<(), Error>
97where
98 Sdata: Stack<Item = i32>,
99 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
100 SeqTok: Clone,
101 BuiltinTok: Clone,
102 O: Write,
103{
104 let val = ctxt.ret_stk.pop()?;
105 ctxt.data_stk.push(val);
106 Ok(())
107}
108
109pub fn bi_eq<BuiltinTok, SeqTok, Sdata, Sexec, O>(
110 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
111) -> Result<(), Error>
112where
113 Sdata: Stack<Item = i32>,
114 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
115 SeqTok: Clone,
116 BuiltinTok: Clone,
117 O: Write,
118{
119 let val1 = ctxt.data_stk.pop()?;
120 let val2 = ctxt.data_stk.pop()?;
121 ctxt.data_stk.push(if val1 == val2 { -1 } else { 0 });
122 Ok(())
123}
124
125pub fn bi_add<BuiltinTok, SeqTok, Sdata, Sexec, O>(
126 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
127) -> Result<(), Error>
128where
129 Sdata: Stack<Item = i32>,
130 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
131 SeqTok: Clone,
132 BuiltinTok: Clone,
133 O: Write,
134{
135 let val1 = ctxt.data_stk.pop()?;
136 let val2 = ctxt.data_stk.pop()?;
137 ctxt.data_stk.push(val1.wrapping_add(val2));
138 Ok(())
139}
140
141pub fn bi_dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
142 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
143) -> Result<(), Error>
144where
145 Sdata: Stack<Item = i32>,
146 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
147 SeqTok: Clone,
148 BuiltinTok: Clone,
149 O: Write,
150{
151 let val1 = *ctxt.data_stk.last()?;
152 ctxt.data_stk.push(val1);
153 Ok(())
154}
155
156pub fn bi_retstk_dup<BuiltinTok, SeqTok, Sdata, Sexec, O>(
157 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
158) -> Result<(), Error>
159where
160 Sdata: Stack<Item = i32>,
161 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
162 SeqTok: Clone,
163 BuiltinTok: Clone,
164 O: Write,
165{
166 let val1 = *ctxt.ret_stk.last()?;
167 ctxt.ret_stk.push(val1);
168 Ok(())
169}
170
171pub fn bi_retstk_swap<BuiltinTok, SeqTok, Sdata, Sexec, O>(
172 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
173) -> Result<(), Error>
174where
175 Sdata: Stack<Item = i32>,
176 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
177 SeqTok: Clone,
178 BuiltinTok: Clone,
179 O: Write,
180{
181 let top = ctxt.ret_stk.pop()?;
182 let bot = ctxt.ret_stk.pop()?;
183 ctxt.ret_stk.push(top);
184 ctxt.ret_stk.push(bot);
185
186 Ok(())
187}
188
189pub fn bi_priv_loop<BuiltinTok, SeqTok, Sdata, Sexec, O>(
190 ctxt: &mut Runtime<BuiltinTok, SeqTok, Sdata, Sexec, O>,
191) -> Result<(), Error>
192where
193 Sdata: Stack<Item = i32>,
194 Sexec: ExecutionStack<BuiltinTok, SeqTok>,
195 SeqTok: Clone,
196 BuiltinTok: Clone,
197 O: Write,
198{
199 let lmt = ctxt.ret_stk.pop()?;
200 let mut idx = ctxt.ret_stk.pop()?;
201
202 idx = idx.checked_add(1).ok_or(Error::BadMath)?;
203
204 if idx == lmt {
205 ctxt.data_stk.push(-1);
206 } else {
207 ctxt.data_stk.push(0);
208 ctxt.ret_stk.push(idx);
209 ctxt.ret_stk.push(lmt);
210 }
211
212 Ok(())
213}