1use crate::push::instructions::Instruction;
2use crate::push::instructions::InstructionCache;
3use crate::push::item::{Item, PushType};
4use crate::push::state::PushState;
5use crate::push::state::*;
6use rand::Rng;
7use std::collections::HashMap;
8
9pub fn load_boolean_instructions(map: &mut HashMap<String, Instruction>) {
10 map.insert(String::from("BOOLEAN.="), Instruction::new(boolean_eq));
11 map.insert(String::from("BOOLEAN.AND"), Instruction::new(boolean_and));
12 map.insert(
13 String::from("BOOLEAN.DEFINE"),
14 Instruction::new(boolean_def),
15 );
16 map.insert(String::from("BOOLEAN.DUP"), Instruction::new(boolean_dup));
17 map.insert(
18 String::from("BOOLEAN.FLUSH"),
19 Instruction::new(boolean_flush),
20 );
21 map.insert(
22 String::from("BOOLEAN.FROMFLOAT"),
23 Instruction::new(boolean_from_float),
24 );
25 map.insert(
26 String::from("BOOLEAN.FROMINTEGER"),
27 Instruction::new(boolean_from_integer),
28 );
29 map.insert(String::from("BOOLEAN.ID"), Instruction::new(boolean_id));
30 map.insert(String::from("BOOLEAN.NOT"), Instruction::new(boolean_not));
31 map.insert(String::from("BOOLEAN.OR"), Instruction::new(boolean_or));
32 map.insert(String::from("BOOLEAN.POP"), Instruction::new(boolean_pop));
33 map.insert(String::from("BOOLEAN.RAND"), Instruction::new(boolean_rand));
34 map.insert(String::from("BOOLEAN.ROT"), Instruction::new(boolean_rot));
35 map.insert(
36 String::from("BOOLEAN.SHOVE"),
37 Instruction::new(boolean_shove),
38 );
39 map.insert(
40 String::from("BOOLEAN.STACKDEPTH"),
41 Instruction::new(boolean_stack_depth),
42 );
43 map.insert(String::from("BOOLEAN.SWAP"), Instruction::new(boolean_swap));
44 map.insert(String::from("BOOLEAN.YANK"), Instruction::new(boolean_yank));
45 map.insert(
46 String::from("BOOLEAN.YANKDUP"),
47 Instruction::new(boolean_yank_dup),
48 );
49}
50
51pub fn boolean_id(push_state: &mut PushState, _instruction_set: &InstructionCache) {
53 push_state.int_stack.push(BOOL_STACK_ID);
54}
55
56pub fn boolean_eq(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
58 if let Some(pv) = push_state.bool_stack.pop_vec(2) {
59 push_state.bool_stack.push(pv[0] == pv[1]);
60 }
61}
62
63pub fn boolean_and(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
65 if let Some(pv) = push_state.bool_stack.pop_vec(2) {
66 push_state.bool_stack.push(pv[0] && pv[1]);
67 }
68}
69
70pub fn boolean_or(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
72 if let Some(pv) = push_state.bool_stack.pop_vec(2) {
73 push_state.bool_stack.push(pv[0] || pv[1]);
74 }
75}
76
77pub fn boolean_def(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
80 if let Some(name) = push_state.name_stack.pop() {
81 if let Some(bval) = push_state.bool_stack.pop() {
82 push_state.name_bindings.insert(
83 name,
84 Item::Literal {
85 push_type: PushType::Bool { val: bval },
86 },
87 );
88 }
89 }
90}
91
92pub fn boolean_dup(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
95 if let Some(pv) = push_state.bool_stack.copy_vec(1) {
96 push_state.bool_stack.push(pv[0]);
97 }
98}
99
100pub fn boolean_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
102 push_state.bool_stack.flush();
103}
104
105pub fn boolean_from_float(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
107 if let Some(pv) = push_state.float_stack.copy_vec(1) {
108 let x = pv[0] == 0.0;
109 push_state.bool_stack.push(x);
110 }
111}
112
113pub fn boolean_from_integer(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
115 if let Some(pv) = push_state.int_stack.copy_vec(1) {
116 let x = pv[0] == 0;
117 push_state.bool_stack.push(x);
118 }
119}
120
121pub fn boolean_not(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
123 if let Some(pv) = push_state.bool_stack.pop() {
124 push_state.bool_stack.push(!pv);
125 }
126}
127
128pub fn boolean_pop(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
130 push_state.bool_stack.pop();
131}
132
133pub fn boolean_rand(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
135 let mut rng = rand::thread_rng();
136 let bval = rng.gen_range(0..2) == 1;
137 push_state.bool_stack.push(bval);
138}
139
140pub fn boolean_rot(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
143 push_state.bool_stack.yank(2);
144}
145
146pub fn boolean_shove(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
149 if let Some(shove_index) = push_state.int_stack.pop() {
150 let corr_index = i32::max(
151 i32::min((push_state.bool_stack.size() as i32) - 1, shove_index),
152 0,
153 ) as usize;
154 push_state.bool_stack.shove(corr_index as usize);
155 }
156}
157
158pub fn boolean_stack_depth(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
160 push_state
161 .int_stack
162 .push(push_state.bool_stack.size() as i32);
163}
164
165pub fn boolean_swap(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
167 push_state.bool_stack.shove(1);
168}
169
170pub fn boolean_yank(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
173 if let Some(index) = push_state.int_stack.pop() {
174 let corr_index = i32::max(
175 i32::min((push_state.bool_stack.size() as i32) - 1, index),
176 0,
177 ) as usize;
178 push_state.bool_stack.yank(corr_index as usize);
179 }
180}
181
182pub fn boolean_yank_dup(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
185 if let Some(idx) = push_state.int_stack.pop() {
186 if let Some(deep_item) = push_state.bool_stack.copy(idx as usize) {
187 push_state.bool_stack.push(deep_item);
188 }
189 }
190}
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 pub fn icache() -> InstructionCache {
196 InstructionCache::new(vec![])
197 }
198
199 #[test]
200 fn boolean_equal_pushes_result() {
201 let mut test_state = PushState::new();
202 test_state.bool_stack.push(true);
203 test_state.bool_stack.push(true);
204 boolean_eq(&mut test_state, &icache());
205 assert_eq!(test_state.bool_stack.pop().unwrap(), true);
206 }
207
208 #[test]
209 fn boolean_and_pushes_result() {
210 let mut test_state = PushState::new();
211 test_state.bool_stack.push(true);
212 test_state.bool_stack.push(false);
213 boolean_and(&mut test_state, &icache());
214 assert_eq!(test_state.bool_stack.pop().unwrap(), false);
215 test_state.bool_stack.push(true);
216 test_state.bool_stack.push(true);
217 boolean_and(&mut test_state, &icache());
218 assert_eq!(test_state.bool_stack.pop().unwrap(), true);
219 }
220
221 #[test]
222 fn boolean_define_creates_name_binding() {
223 let mut test_state = PushState::new();
224 test_state.bool_stack.push(true);
225 test_state.name_stack.push(String::from("TEST"));
226 boolean_def(&mut test_state, &icache());
227 assert_eq!(
228 *test_state.name_bindings.get("TEST").unwrap().to_string(),
229 Item::bool(true).to_string()
230 );
231 }
232
233 #[test]
234 fn boolean_dup_copies_top_element() {
235 let mut test_state = PushState::new();
236 test_state.bool_stack.push(false);
237 boolean_dup(&mut test_state, &icache());
238 assert_eq!(test_state.bool_stack.to_string(), "FALSE FALSE");
239 }
240
241 #[test]
242 fn boolean_flush_empties_stack() {
243 let mut test_state = PushState::new();
244 test_state.bool_stack.push(true);
245 test_state.bool_stack.push(false);
246 boolean_flush(&mut test_state, &icache());
247 assert_eq!(test_state.bool_stack.to_string(), "");
248 }
249
250 #[test]
251 fn boolean_from_float_compares_to_zero() {
252 let mut test_state = PushState::new();
253 test_state.float_stack.push(0.0);
254 boolean_from_float(&mut test_state, &icache());
255 assert_eq!(test_state.bool_stack.to_string(), "TRUE");
256 test_state.float_stack.push(0.01);
257 boolean_from_float(&mut test_state, &icache());
258 assert_eq!(test_state.bool_stack.to_string(), "FALSE TRUE");
259 }
260
261 #[test]
262 fn boolean_from_integer_compares_to_zero() {
263 let mut test_state = PushState::new();
264 test_state.int_stack.push(0);
265 boolean_from_integer(&mut test_state, &icache());
266 assert_eq!(test_state.bool_stack.to_string(), "TRUE");
267 test_state.int_stack.push(1);
268 boolean_from_integer(&mut test_state, &icache());
269 assert_eq!(test_state.bool_stack.to_string(), "FALSE TRUE");
270 }
271
272 #[test]
273 fn boolean_or_pushes_result() {
274 let mut test_state = PushState::new();
275 test_state.bool_stack.push(true);
276 test_state.bool_stack.push(false);
277 boolean_or(&mut test_state, &icache());
278 assert_eq!(test_state.bool_stack.pop().unwrap(), true);
279 test_state.bool_stack.push(false);
280 test_state.bool_stack.push(false);
281 boolean_or(&mut test_state, &icache());
282 assert_eq!(test_state.bool_stack.pop().unwrap(), false);
283 }
284
285 #[test]
286 fn boolean_not_pushes_result() {
287 let mut test_state = PushState::new();
288 test_state.bool_stack.push(true);
289 boolean_not(&mut test_state, &icache());
290 assert_eq!(test_state.bool_stack.pop().unwrap(), false);
291 test_state.bool_stack.push(false);
292 boolean_not(&mut test_state, &icache());
293 assert_eq!(test_state.bool_stack.pop().unwrap(), true);
294 }
295
296 #[test]
297 fn boolean_pop_removes_top_element() {
298 let mut test_state = PushState::new();
299 test_state.bool_stack.push(true);
300 test_state.bool_stack.push(false);
301 boolean_pop(&mut test_state, &icache());
302 assert_eq!(test_state.bool_stack.to_string(), "TRUE");
303 }
304
305 #[test]
306 fn boolean_rand_generates_value() {
307 let mut test_state = PushState::new();
308 boolean_rand(&mut test_state, &icache());
309 assert_eq!(test_state.bool_stack.size(), 1);
310 }
311
312 #[test]
313 fn boolean_rot_shuffles_elements() {
314 let mut test_state = PushState::new();
315 test_state.bool_stack.push(true);
316 test_state.bool_stack.push(true);
317 test_state.bool_stack.push(false);
318 assert_eq!(
319 test_state.bool_stack.to_string(),
320 "FALSE TRUE TRUE"
321 );
322 boolean_rot(&mut test_state, &icache());
323 assert_eq!(
324 test_state.bool_stack.to_string(),
325 "TRUE FALSE TRUE"
326 );
327 }
328
329 #[test]
330 fn boolean_shove_inserts_at_right_position() {
331 let mut test_state = PushState::new();
332 test_state.bool_stack.push(true);
333 test_state.bool_stack.push(true);
334 test_state.bool_stack.push(true);
335 test_state.bool_stack.push(false);
336 assert_eq!(
337 test_state.bool_stack.to_string(),
338 "FALSE TRUE TRUE TRUE"
339 );
340 test_state.int_stack.push(2);
341 boolean_shove(&mut test_state, &icache());
342 assert_eq!(
343 test_state.bool_stack.to_string(),
344 "TRUE TRUE FALSE TRUE"
345 );
346 }
347
348 #[test]
349 fn boolean_stack_depth_returns_size() {
350 let mut test_state = PushState::new();
351 test_state.bool_stack.push(true);
352 test_state.bool_stack.push(true);
353 test_state.bool_stack.push(true);
354 test_state.bool_stack.push(false);
355 boolean_stack_depth(&mut test_state, &icache());
356 assert_eq!(test_state.int_stack.to_string(), "4");
357 }
358
359 #[test]
360 fn boolean_swaps_top_elements() {
361 let mut test_state = PushState::new();
362 test_state.bool_stack.push(true);
363 test_state.bool_stack.push(false);
364 assert_eq!(test_state.bool_stack.to_string(), "FALSE TRUE");
365 boolean_swap(&mut test_state, &icache());
366 assert_eq!(test_state.bool_stack.to_string(), "TRUE FALSE");
367 }
368
369 #[test]
370 fn boolean_yank_brings_item_to_top() {
371 let mut test_state = PushState::new();
372 test_state.bool_stack.push(true);
373 test_state.bool_stack.push(false);
374 test_state.bool_stack.push(true);
375 test_state.bool_stack.push(true);
376 assert_eq!(
377 test_state.bool_stack.to_string(),
378 "TRUE TRUE FALSE TRUE"
379 );
380 test_state.int_stack.push(2);
381 boolean_yank(&mut test_state, &icache());
382 assert_eq!(
383 test_state.bool_stack.to_string(),
384 "FALSE TRUE TRUE TRUE"
385 );
386 }
387
388 #[test]
389 fn boolean_yank_dup_copies_item_to_top() {
390 let mut test_state = PushState::new();
391 test_state.bool_stack.push(true);
392 test_state.bool_stack.push(false);
393 test_state.bool_stack.push(true);
394 test_state.bool_stack.push(true);
395 assert_eq!(
396 test_state.bool_stack.to_string(),
397 "TRUE TRUE FALSE TRUE"
398 );
399 test_state.int_stack.push(2);
400 boolean_yank_dup(&mut test_state, &icache());
401 assert_eq!(
402 test_state.bool_stack.to_string(),
403 "FALSE TRUE TRUE FALSE TRUE"
404 );
405 }
406}