1use crate::push::instructions::Instruction;
2use crate::push::instructions::InstructionCache;
3use crate::push::item::Item;
4use crate::push::random::CodeGenerator;
5use crate::push::stack::PushStack;
6use crate::push::state::PushState;
7use crate::push::state::*;
8use std::cmp;
9use std::collections::HashMap;
10
11pub fn load_code_instructions(map: &mut HashMap<String, Instruction>) {
16 map.insert(String::from("CODE.="), Instruction::new(code_eq));
17 map.insert(String::from("CODE.APPEND"), Instruction::new(code_append));
18 map.insert(String::from("CODE.ATOM"), Instruction::new(code_item));
19 map.insert(String::from("CODE.CAR"), Instruction::new(code_first));
20 map.insert(String::from("CODE.CDR"), Instruction::new(code_rest));
21 map.insert(String::from("CODE.CONS"), Instruction::new(code_cons));
22 map.insert(
23 String::from("CODE.CONTAINER"),
24 Instruction::new(code_container),
25 );
26 map.insert(
27 String::from("CODE.CONTAINS"),
28 Instruction::new(code_contains),
29 );
30 map.insert(String::from("CODE.DEFINE"), Instruction::new(code_define));
31 map.insert(
32 String::from("CODE.DEFINITION"),
33 Instruction::new(code_definition),
34 );
35 map.insert(
36 String::from("CODE.DISCREPANCY"),
37 Instruction::new(code_discrepancy),
38 );
39 map.insert(String::from("CODE.DO"), Instruction::new(code_do));
40 map.insert(String::from("CODE.DO*"), Instruction::new(code_pop_and_do));
41 map.insert(String::from("CODE.LOOP"), Instruction::new(code_loop));
42 map.insert(String::from("CODE.DUP"), Instruction::new(code_dup));
43 map.insert(String::from("CODE.EXTRACT"), Instruction::new(code_extract));
44 map.insert(String::from("CODE.FLUSH"), Instruction::new(code_flush));
45 map.insert(
46 String::from("CODE.FROMBOOLEAN"),
47 Instruction::new(code_from_bool),
48 );
49 map.insert(
50 String::from("CODE.FROMFLOAT"),
51 Instruction::new(code_from_float),
52 );
53 map.insert(
54 String::from("CODE.FROMINTEGER"),
55 Instruction::new(code_from_int),
56 );
57 map.insert(
58 String::from("CODE.FROMNAME"),
59 Instruction::new(code_from_name),
60 );
61 map.insert(String::from("CODE.ID"), Instruction::new(code_id));
62 map.insert(String::from("CODE.IF"), Instruction::new(code_if));
63 map.insert(String::from("CODE.INSERT"), Instruction::new(code_insert));
64 map.insert(String::from("CODE.LENGTH"), Instruction::new(code_length));
65 map.insert(String::from("CODE.LIST"), Instruction::new(code_list));
66 map.insert(String::from("CODE.MEMBER"), Instruction::new(code_member));
67 map.insert(String::from("CODE.NOOP"), Instruction::new(code_noop));
68 map.insert(String::from("CODE.NTH"), Instruction::new(code_nth));
69 map.insert(String::from("CODE.NULL"), Instruction::new(code_null));
70 map.insert(String::from("CODE.POP"), Instruction::new(code_pop));
71 map.insert(
72 String::from("CODE.POSITION"),
73 Instruction::new(code_position),
74 );
75 map.insert(String::from("CODE.PRINT"), Instruction::new(code_print));
76 map.insert(String::from("CODE.QUOTE"), Instruction::new(code_quote));
77 map.insert(String::from("CODE.RAND"), Instruction::new(code_rand));
78 map.insert(String::from("CODE.ROT"), Instruction::new(code_rot));
79 map.insert(String::from("CODE.SHOVE"), Instruction::new(code_shove));
80 map.insert(String::from("CODE.SIZE"), Instruction::new(code_size));
81 map.insert(
82 String::from("CODE.STACKDEPTH"),
83 Instruction::new(code_stack_depth),
84 );
85 map.insert(String::from("CODE.SUBST"), Instruction::new(code_subst));
86 map.insert(String::from("CODE.SWAP"), Instruction::new(code_swap));
87 map.insert(String::from("CODE.YANK"), Instruction::new(code_yank));
88 map.insert(
89 String::from("CODE.YANKDUP"),
90 Instruction::new(code_yank_dup),
91 );
92}
93
94pub fn code_id(push_state: &mut PushState, _instruction_set: &InstructionCache) {
96 push_state.int_stack.push(CODE_STACK_ID);
97}
98
99pub fn code_eq(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
102 if let Some(pv) = push_state.code_stack.copy_vec(2) {
103 push_state
104 .bool_stack
105 .push(pv[0].to_string() == pv[1].to_string());
106 }
107}
108
109pub fn code_append(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
114 if let Some(pv) = push_state.code_stack.pop_vec(2) {
115 push_state.code_stack.push(Item::List {
116 items: PushStack::from_vec(pv),
117 });
118 }
119}
120
121pub fn code_item(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
124 push_state.bool_stack.push(
126 push_state.code_stack.last_eq(&Item::int(0))
127 || push_state.code_stack.last_eq(&Item::noop()),
128 );
129}
130
131pub fn code_first(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
136 if push_state.code_stack.last_eq(&Item::empty_list()) {
137 match push_state.code_stack.pop() {
138 Some(Item::List { mut items }) => {
139 if let Some(item) = items.pop() {
140 push_state.code_stack.push(item);
141 }
142 }
143 _ => (),
144 }
145 }
146}
147
148pub fn code_rest(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
154 match push_state.code_stack.pop() {
155 Some(Item::List { mut items }) => {
156 items.pop();
157 push_state.code_stack.push(Item::List { items: items });
158 }
159 _ => (),
160 }
161}
162
163pub fn code_cons(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
168 if let Some(pv) = push_state.code_stack.pop_vec(2) {
169 let mut consblock = PushStack::new();
170 for i in (0..2).rev() {
171 match &pv[i] {
172 Item::Literal { push_type: _ } => {
173 consblock.push(pv[i].clone());
174 }
175 Item::List { items: a } => {
176 if let Some(vec) = a.copy_vec(a.size()) {
177 consblock.push_vec(vec)
178 }
179 }
180 _ => (),
181 }
182 }
183 push_state.code_stack.push(Item::List { items: consblock });
184 }
185}
186
187pub fn code_container(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
194 if let Some(code) = push_state.code_stack.copy_vec(2) {
195 match Item::container(&code[1], &code[0]) {
196 Ok(container) => push_state.code_stack.push(container),
197 Err(_) => push_state.code_stack.push(Item::empty_list()),
198 }
199 }
200}
201
202pub fn code_contains(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
205 if let Some(ov) = push_state.code_stack.copy_vec(2) {
206 let first_el = ov[1].to_string();
207 let code_str = ov[0].to_string();
208 if first_el.contains(&code_str) {
209 push_state.bool_stack.push(true);
210 } else {
211 push_state.bool_stack.push(false);
212 }
213 }
214}
215
216pub fn code_define(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
219 if let Some(name) = push_state.name_stack.pop() {
220 if let Some(instruction) = push_state.code_stack.pop() {
221 push_state.name_bindings.insert(name, instruction);
222 }
223 }
224}
225
226pub fn code_definition(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
231 if let Some(name) = push_state.name_stack.pop() {
232 if let Some(instruction) = push_state.name_bindings.get(&*name) {
233 push_state.code_stack.push(instruction.clone());
234 }
235 }
236}
237pub fn code_discrepancy(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
247 let mut discrepancy = 0;
248 if let Some(ov) = push_state.code_stack.copy_vec(2) {
249 match &ov[0] {
250 Item::List { items: fstlist } => {
251 match &ov[1] {
252 Item::List { items: scdlist } => {
253 if let Some(fstvec) = fstlist.copy_vec(fstlist.size()) {
255 for (i, x) in fstvec.iter().rev().enumerate() {
256 if let Some(val) = scdlist.equal_at(i, x) {
257 if !val {
258 discrepancy += 1;
259 }
260 }
261 }
262 }
263 discrepancy =
264 discrepancy + (fstlist.size() as i32 - scdlist.size() as i32).abs();
265 }
266 _ => {
267 discrepancy = if ov[0].to_string() != ov[1].to_string() {
268 1
269 } else {
270 0
271 }
272 }
273 }
274 }
275 _ => {
276 discrepancy = if ov[0].to_string() != ov[1].to_string() {
277 1
278 } else {
279 0
280 }
281 }
282 }
283 push_state.int_stack.push(discrepancy);
284 }
285}
286
287pub fn code_do(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
292 if let Some(instruction) = push_state.code_stack.copy(0) {
293 push_state.exec_stack.push(Item::InstructionMeta {
294 name: "CODE.POP".to_string(),
295 });
296 push_state.exec_stack.push(instruction);
297 }
298}
299
300pub fn code_pop_and_do(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
302 if let Some(instruction) = push_state.code_stack.copy(0) {
303 push_state.exec_stack.push(instruction);
304 push_state.exec_stack.push(Item::InstructionMeta {
305 name: "CODE.POP".to_string(),
306 });
307 }
308}
309
310pub fn code_loop(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
322 if let Some(body) = push_state.code_stack.pop() {
323 if let Some(index) = push_state.index_stack.copy(0) {
324 if index.current < index.destination {
325 let updated_loop = Item::list(vec![
326 body.clone(),
327 Item::instruction("CODE.LOOP".to_string()),
328 Item::instruction("INDEX.INCREASE".to_string()),
329 ]);
330 push_state.exec_stack.push(updated_loop);
331 push_state.exec_stack.push(body);
332 } else {
333 push_state.index_stack.pop();
334 }
335 }
336 }
337}
338
339pub fn code_dup(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
342 if let Some(instruction) = push_state.code_stack.copy(0) {
343 push_state.code_stack.push(instruction);
344 }
345}
346
347pub fn code_extract(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
355 if let Some(sub_idx) = push_state.int_stack.pop() {
356 if let Some(code) = push_state.code_stack.get(0) {
357 let total_size = Item::size(code);
358 let norm_idx = sub_idx.rem_euclid(total_size as i32);
359 match Item::traverse(&code, norm_idx as usize) {
360 Ok(el) => push_state.code_stack.push(el),
361 Err(_) => (),
362 };
363 }
364 }
365}
366
367pub fn code_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
369 push_state.code_stack.flush();
370}
371
372pub fn code_from_bool(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
375 if let Some(bval) = push_state.bool_stack.pop() {
376 push_state.code_stack.push(Item::bool(bval));
377 }
378}
379pub fn code_from_float(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
381 if let Some(fval) = push_state.float_stack.pop() {
382 push_state.code_stack.push(Item::float(fval));
383 }
384}
385
386pub fn code_from_int(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
388 if let Some(ival) = push_state.int_stack.pop() {
389 push_state.code_stack.push(Item::int(ival));
390 }
391}
392
393pub fn code_from_name(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
395 if let Some(nval) = push_state.name_stack.pop() {
396 push_state.code_stack.push(Item::id(nval.to_string()));
397 }
398}
399
400pub fn code_if(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
405 if let Some(code) = push_state.code_stack.pop_vec(2) {
406 if let Some(exec_second) = push_state.bool_stack.pop() {
407 if exec_second {
408 push_state.exec_stack.push(code[0].clone());
410 } else {
411 push_state.exec_stack.push(code[1].clone());
413 }
414 }
415 }
416}
417
418pub fn code_insert(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
422 if let Some(sub_idx) = push_state.int_stack.pop() {
423 if let Some(code_to_be_inserted) = push_state.code_stack.copy(1) {
424 let _ = Item::insert(
425 push_state.code_stack.get_mut(0).unwrap(),
426 &code_to_be_inserted,
427 sub_idx as usize,
428 );
429 }
430 }
431}
432
433pub fn code_length(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
438 if let Some(top_item) = push_state.code_stack.get(0) {
439 match top_item {
440 Item::List { items } => push_state.int_stack.push(items.size() as i32),
441 _ => push_state.int_stack.push(1),
442 }
443 }
444}
445
446pub fn code_list(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
448 if let Some(top_items) = push_state.code_stack.copy_vec(2) {
449 push_state
450 .code_stack
451 .push(Item::list(vec![top_items[0].clone(), top_items[1].clone()]));
452 }
453}
454
455pub fn code_member(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
458 if let Some(ov) = push_state.code_stack.copy_vec(2) {
459 let top_el = ov[1].to_string();
460 let sec_el = ov[0].to_string();
461 if sec_el.contains(&top_el) {
462 push_state.bool_stack.push(true);
463 } else {
464 push_state.bool_stack.push(false);
465 }
466 }
467}
468
469pub fn code_noop(_push_state: &mut PushState, _instruction_cache: &InstructionCache) {}
471
472pub fn code_nth(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
477 if let Some(sub_idx) = push_state.int_stack.pop() {
478 if let Some(code) = push_state.code_stack.get(0) {
479 let total_size = Item::shallow_size(code);
480 let idx = sub_idx.rem_euclid(total_size as i32);
481 let mut item_to_push = Item::empty_list();
482 if idx == 0 {
483 item_to_push = code.clone();
484 }
485 match code {
486 Item::List { items } => {
487 if let Some(nth_item) = items.get(idx as usize - 1) {
488 item_to_push = nth_item.clone();
489 }
490 }
491 _ => (),
492 }
493 push_state.code_stack.push(item_to_push);
494 }
495 }
496}
497
498pub fn code_null(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
501 if let Some(code) = push_state.code_stack.get(0) {
502 let mut is_null = false;
503 match code {
504 Item::List { items } => {
505 if items.size() == 0 {
506 is_null = true;
507 }
508 }
509 _ => (),
510 }
511 push_state.bool_stack.push(is_null);
512 }
513}
514
515pub fn code_pop(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
517 push_state.code_stack.pop();
518}
519
520pub fn code_position(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
523 if let Some(code) = push_state.code_stack.copy_vec(2) {
524 match Item::contains(&code[1], &code[0], 0) {
525 Ok(pos) => push_state.int_stack.push(pos as i32),
526 Err(()) => push_state.int_stack.push(-1),
527 }
528 }
529}
530
531pub fn code_print(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
533 if push_state.code_stack.size() > 0 {
534 let code_str = push_state.code_stack.to_string();
535 push_state.name_stack.push(code_str);
536
537 }
538}
539
540pub fn code_quote(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
544 if let Some(exec_code) = push_state.exec_stack.pop() {
545 push_state.code_stack.push(exec_code);
546 }
547}
548
549pub fn code_rand(push_state: &mut PushState, instruction_cache: &InstructionCache) {
554 if let Some(size_limit) = push_state.int_stack.pop() {
555 let limit = cmp::min(
556 i32::abs(size_limit),
557 i32::abs(push_state.configuration.max_points_in_random_expressions),
558 );
559 if let Some(rand_item) =
560 CodeGenerator::random_code(&push_state, &instruction_cache, limit as usize)
561 {
562 push_state.code_stack.push(rand_item);
563 }
564 }
565}
566
567pub fn code_rot(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
570 push_state.code_stack.yank(2);
571}
572
573pub fn code_shove(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
576 if let Some(shove_index) = push_state.int_stack.pop() {
577 let corr_index = i32::max(
578 i32::min((push_state.code_stack.size() as i32) - 1, shove_index),
579 0,
580 ) as usize;
581 push_state.code_stack.shove(corr_index as usize);
582 }
583}
584
585pub fn code_size(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
588 if let Some(code) = push_state.code_stack.get(0) {
589 push_state.int_stack.push(Item::size(&code) as i32);
590 }
591}
592
593pub fn code_stack_depth(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
595 push_state
596 .int_stack
597 .push(push_state.code_stack.size() as i32);
598}
599
600pub fn code_subst(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
606 if let Some(code) = push_state.code_stack.pop_vec(3) {
607 let mut target = code[2].clone();
611 if Item::substitute(&mut target, &code[0], &code[1]) {
612 push_state.code_stack.push(code[1].clone());
614 } else {
615 push_state.code_stack.push(target);
617 }
618 }
619}
620
621pub fn code_swap(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
623 push_state.code_stack.shove(1);
624}
625
626pub fn code_yank(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
629 if let Some(index) = push_state.int_stack.pop() {
630 let corr_index = i32::max(
631 i32::min((push_state.code_stack.size() as i32) - 1, index),
632 0,
633 ) as usize;
634 push_state.code_stack.yank(corr_index as usize);
635 }
636}
637
638pub fn code_yank_dup(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
641 if let Some(index) = push_state.int_stack.pop() {
642 let corr_index = i32::max(
643 i32::min((push_state.code_stack.size() as i32) - 1, index),
644 0,
645 ) as usize;
646 if let Some(deep_item) = push_state.code_stack.copy(corr_index as usize) {
647 push_state.code_stack.push(deep_item);
648 }
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use super::*;
655 use crate::push::index::Index;
656 use crate::push::parser::PushParser;
657 use crate::push::instructions::InstructionSet;
658
659 pub fn icache() -> InstructionCache {
660 InstructionCache::new(vec![])
661 }
662
663 #[test]
664 fn code_eq_pushes_true_when_elements_equal() {
665 let mut test_state = PushState::new();
666 test_state.code_stack.push(Item::int(1));
667 test_state.code_stack.push(Item::int(1));
668 code_eq(&mut test_state, &icache());
669 assert_eq!(test_state.code_stack.size(), 2);
670 if let Some(val) = test_state.bool_stack.pop() {
671 assert_eq!(val, true, "Must be true in case of equality");
672 } else {
673 assert!(false, "Expected bool value");
674 }
675 }
676
677 #[test]
678 fn code_eq_pushes_false_when_elements_unequal() {
679 let mut test_state = PushState::new();
680 test_state.code_stack.push(Item::int(1));
681 test_state.code_stack.push(Item::int(2));
682 code_eq(&mut test_state, &icache());
683 assert_eq!(test_state.code_stack.size(), 2);
684 if let Some(val) = test_state.bool_stack.pop() {
685 assert_eq!(val, false, "Must be false in case of inequality");
686 } else {
687 assert!(false, "Expected bool value");
688 }
689 }
690
691 #[test]
692 fn code_append_pushes_block_when_finding_literals() {
693 let mut test_state = PushState::new();
694 test_state.code_stack.push(Item::int(1));
695 test_state.code_stack.push(Item::int(2));
696 code_append(&mut test_state, &icache());
697 assert_eq!(test_state.code_stack.size(), 1, "Excpected single element");
698 assert!(
699 test_state.code_stack.last_eq(&Item::empty_list()),
700 "Expected Code Block"
701 );
702 }
703
704 #[test]
705 fn code_item_pushes_true_when_no_list_found() {
706 let mut test_state = PushState::new();
707 test_state.code_stack.push(Item::int(0));
708 code_item(&mut test_state, &icache());
709 assert!(
710 test_state.bool_stack.last_eq(&true),
711 "Should push true for Literal"
712 );
713 test_state = PushState::new();
714 test_state.code_stack.push(Item::noop());
715 code_item(&mut test_state, &icache());
716 assert!(
717 test_state.bool_stack.last_eq(&true),
718 "Should push true for Instruction"
719 );
720 test_state = PushState::new();
721 test_state.code_stack.push(Item::empty_list());
722 code_item(&mut test_state, &icache());
723 assert!(
724 test_state.bool_stack.last_eq(&false),
725 "Should push false for Code Block"
726 );
727 }
728
729 #[test]
730 fn code_first_pushes_first_element_when_cb_is_found() {
731 let mut test_state = PushState::new();
732 test_state
733 .code_stack
734 .push(Item::list(vec![Item::int(1), Item::int(2), Item::int(3)]));
735 code_first(&mut test_state, &icache());
736 assert_eq!(test_state.code_stack.to_string(), "3");
737 }
738
739 #[test]
740 fn code_rest_pushes_all_except_first_element() {
741 let mut test_state = PushState::new();
742 test_state
743 .code_stack
744 .push(Item::list(vec![Item::int(1), Item::int(2), Item::int(3)]));
745 assert_eq!(
746 test_state.code_stack.to_string(),
747 "( 3 2 1 )"
748 );
749 code_rest(&mut test_state, &icache());
750 assert_eq!(
751 test_state.code_stack.to_string(),
752 "( 2 1 )"
753 );
754 }
755
756 #[test]
757 fn code_cons_appends_in_reverse_order() {
758 let mut test_state = PushState::new();
759 test_state.code_stack.push(Item::int(1));
760 test_state.code_stack.push(Item::int(2));
761 assert_eq!(
762 test_state.code_stack.to_string(),
763 "2 1"
764 );
765 code_cons(&mut test_state, &icache());
766 assert_eq!(
767 test_state.code_stack.to_string(),
768 "( 1 2 )"
769 );
770 }
771
772 #[test]
773 fn code_container_finds_subelement() {
774 let mut test_state = PushState::new();
775 test_state
777 .code_stack
778 .push(Item::list(vec![Item::int(1), Item::int(2)]));
779 test_state.code_stack.push(Item::list(vec![
780 Item::list(vec![
781 Item::int(3),
782 Item::list(vec![Item::int(1), Item::int(2)]),
783 Item::list(vec![Item::int(3), Item::int(3)]),
784 Item::int(3),
785 ]),
786 Item::int(4),
787 Item::int(5),
788 ]));
789 code_container(&mut test_state, &icache());
790 assert!(test_state
792 .code_stack
793 .to_string()
794 .starts_with("( 3 ( 3 3 ) ( 2 1 ) 3"));
795 }
796
797 #[test]
798 fn code_contains_pushes_true_if_second_contains_first() {
799 let mut test_state = PushState::new();
800 test_state
802 .code_stack
803 .push(Item::list(vec![Item::int(1), Item::int(2)]));
804 test_state.code_stack.push(Item::list(vec![
805 Item::list(vec![
806 Item::int(3),
807 Item::list(vec![Item::int(1), Item::int(2)]),
808 Item::list(vec![Item::int(3), Item::int(3)]),
809 Item::int(3),
810 ]),
811 Item::int(4),
812 Item::int(5),
813 ]));
814 code_contains(&mut test_state, &icache());
815 assert_eq!(test_state.bool_stack.to_string(), "TRUE");
816 }
817
818 #[test]
819 fn code_define_creates_name_binding() {
820 let mut test_state = PushState::new();
821 test_state.code_stack.push(Item::int(2));
822 test_state.name_stack.push(String::from("TEST"));
823 code_define(&mut test_state, &icache());
824 assert_eq!(
825 *test_state.name_bindings.get("TEST").unwrap().to_string(),
826 Item::int(2).to_string()
827 );
828 }
829
830 #[test]
831 fn code_definition_pushes_to_code_stack() {
832 let mut test_state = PushState::new();
833 test_state
834 .name_bindings
835 .insert(String::from("TEST"), Item::int(2));
836 test_state.name_stack.push(String::from("TEST"));
837 code_definition(&mut test_state, &icache());
838 assert_eq!(
839 test_state.code_stack.pop().unwrap().to_string(),
840 Item::int(2).to_string()
841 );
842 }
843
844 #[test]
845 fn code_discrepancy_calculates_zero_discrepancy_correctly() {
846 let mut test_state = PushState::new();
847 test_state
849 .code_stack
850 .push(Item::list(vec![Item::int(1), Item::int(2)]));
851 test_state
852 .code_stack
853 .push(Item::list(vec![Item::int(1), Item::int(2)]));
854 code_discrepancy(&mut test_state, &icache());
855 assert_eq!(test_state.int_stack.to_string(), "0");
856 }
857
858 #[test]
859 fn code_discrepancy_calculates_discrepancy_correctly() {
860 let mut test_state = PushState::new();
861 test_state
863 .code_stack
864 .push(Item::list(vec![Item::int(0), Item::int(2)]));
865 test_state
866 .code_stack
867 .push(Item::list(vec![Item::int(1), Item::int(2)]));
868 code_discrepancy(&mut test_state, &icache());
869 assert_eq!(test_state.int_stack.to_string(), "1");
870 }
871
872 #[test]
873 fn code_do_adds_instruction_to_excecution_stack() {
874 let mut test_state = PushState::new();
875 test_state.code_stack.push(Item::int(9));
876 code_do(&mut test_state, &icache());
877 assert_eq!(
878 test_state.exec_stack.to_string(),
879 "9 CODE.POP"
880 );
881 }
882
883 #[test]
884 fn code_pop_and_do_adds_instruction_to_excecution_stack() {
885 let mut test_state = PushState::new();
886 test_state.code_stack.push(Item::int(9));
887 code_pop_and_do(&mut test_state, &icache());
888 assert_eq!(
889 test_state.exec_stack.to_string(),
890 "CODE.POP 9"
891 );
892 }
893
894 #[test]
895 fn code_loop_pushes_body_and_updated_loop() {
896 let mut test_state = PushState::new();
897 test_state.code_stack.push(Item::noop());
898 test_state.index_stack.push(Index::new(3));
899 code_loop(&mut test_state, &icache());
900 assert_eq!(test_state.exec_stack.to_string(), "NOOP ( INDEX.INCREASE CODE.LOOP NOOP )");
901 }
902
903 #[test]
904 fn code_loop_removes_index_when_terminated() {
905 let mut test_state = PushState::new();
906 test_state.code_stack.push(Item::noop());
907 let mut test_index = Index::new(3);
908 test_index.current = 3;
909 test_state.index_stack.push(test_index);
910 code_loop(&mut test_state, &icache());
911 assert_eq!(test_state.index_stack.to_string(), "");
912 assert_eq!(test_state.exec_stack.to_string(), "");
913 }
914
915 #[test]
916 fn code_dup_duplicates_top_element() {
917 let mut test_state = PushState::new();
918 test_state.code_stack.push(Item::noop());
919 code_dup(&mut test_state, &icache());
920 assert_eq!(
921 test_state.code_stack.to_string(),
922 "NOOP NOOP"
923 );
924 }
925
926 #[test]
927 fn code_flush_empties_stack() {
928 let mut test_state = PushState::new();
929 test_state
931 .code_stack
932 .push(Item::list(vec![Item::int(0), Item::int(2)]));
933 test_state
934 .code_stack
935 .push(Item::list(vec![Item::int(1), Item::int(2)]));
936 code_flush(&mut test_state, &icache());
937 assert_eq!(test_state.code_stack.to_string(), "");
938 }
939
940 #[test]
941 fn code_from_bool_pushes_literal() {
942 let mut test_state = PushState::new();
943 test_state.bool_stack.push(true);
944 code_from_bool(&mut test_state, &icache());
945 assert_eq!(test_state.code_stack.to_string(), "TRUE");
946 }
947
948 #[test]
949 fn code_if_pushes_second_item_when_true() {
950 let mut test_state = PushState::new();
951 test_state.bool_stack.push(true);
952 test_state.code_stack.push(Item::int(2));
953 test_state.code_stack.push(Item::int(1));
954 code_if(&mut test_state, &icache());
955 assert_eq!(test_state.exec_stack.to_string(), "2");
956 assert_eq!(test_state.code_stack.to_string(), "");
957 assert_eq!(test_state.bool_stack.to_string(), "");
958 }
959
960 #[test]
961 fn code_if_pushes_first_item_when_false() {
962 let mut test_state = PushState::new();
963 test_state.bool_stack.push(false);
964 test_state.code_stack.push(Item::int(2));
965 test_state.code_stack.push(Item::int(1));
966 code_if(&mut test_state, &icache());
967 assert_eq!(test_state.exec_stack.to_string(), "1");
968 assert_eq!(test_state.code_stack.to_string(), "");
969 assert_eq!(test_state.bool_stack.to_string(), "");
970 }
971
972 #[test]
973 fn code_extract_finds_correct_subelement() {
974 let mut test_state = PushState::new();
975 let test_item = Item::list(vec![
976 Item::int(4),
977 Item::list(vec![Item::int(3)]),
978 Item::int(2),
979 Item::int(1),
980 ]);
981 test_state.int_stack.push(10);
984 test_state.code_stack.push(test_item);
985 code_extract(&mut test_state, &icache());
986 assert_eq!(test_state.int_stack.to_string(), "");
987 assert_eq!(
988 test_state.code_stack.to_string(),
989 "3 ( 1 2 ( 3 ) 4 )"
990 );
991 }
992
993 #[test]
994 fn code_insert_replaces_element() {
995 let mut test_state = PushState::new();
996 test_state.int_stack.push(4);
997 let test_container = Item::list(vec![
998 Item::int(4),
999 Item::list(vec![Item::int(3)]),
1000 Item::int(2),
1001 Item::int(1),
1002 ]);
1003 let test_item = Item::int(5);
1004 test_state.code_stack.push(test_item);
1005 test_state.code_stack.push(test_container);
1006 code_insert(&mut test_state, &icache());
1007 assert_eq!(test_state.int_stack.to_string(), "");
1008 assert_eq!(
1009 test_state.code_stack.to_string(),
1010 "( 1 2 ( 5 ) 4 ) 5"
1011 );
1012 }
1013
1014 #[test]
1015 fn code_insert_does_nothing_when_index_too_big() {
1016 let mut test_state = PushState::new();
1017 test_state.int_stack.push(4);
1018 let test_container = Item::list(vec![Item::int(2), Item::int(1)]);
1019 let test_item = Item::int(5);
1020 test_state.code_stack.push(test_item);
1021 test_state.code_stack.push(test_container);
1022 code_insert(&mut test_state, &icache());
1023 assert_eq!(test_state.int_stack.to_string(), "");
1024 assert_eq!(
1025 test_state.code_stack.to_string(),
1026 "( 1 2 ) 5"
1027 );
1028 }
1029
1030 #[test]
1031 fn code_length_pushes_top_list_size() {
1032 let mut test_state = PushState::new();
1033 test_state.code_stack.push(Item::list(vec![
1034 Item::int(2),
1035 Item::int(1),
1036 Item::list(vec![Item::int(0), Item::float(2.3)]),
1037 ]));
1038 code_length(&mut test_state, &icache());
1039 assert_eq!(test_state.int_stack.to_string(), "3");
1040 }
1041
1042 #[test]
1043 fn code_list_pushes_lists_including_top_items() {
1044 let mut test_state = PushState::new();
1045 test_state
1046 .code_stack
1047 .push(Item::list(vec![Item::int(0), Item::float(2.3)]));
1048 test_state.code_stack.push(Item::int(2));
1049 code_list(&mut test_state, &icache());
1050 assert_eq!(test_state.code_stack.to_string(), "( 2 ( 2.300 0 ) ) 2 ( 2.300 0 )");
1051 }
1052
1053 #[test]
1054 fn code_nth_ignores_nested_lists() {
1055 let mut test_state = PushState::new();
1056 let test_item = Item::list(vec![
1057 Item::int(4),
1058 Item::list(vec![Item::int(3)]),
1059 Item::int(2),
1060 Item::int(1),
1061 ]);
1062 test_state.int_stack.push(9);
1065 test_state.code_stack.push(test_item);
1066 code_nth(&mut test_state, &icache());
1067 assert_eq!(test_state.int_stack.to_string(), "");
1068 assert_eq!(
1069 test_state.code_stack.to_string(),
1070 "4 ( 1 2 ( 3 ) 4 )"
1071 );
1072 }
1073
1074 #[test]
1075 fn code_null_pushes_true_for_empty_list() {
1076 let mut test_state = PushState::new();
1077 test_state.code_stack.push(Item::empty_list());
1078 code_null(&mut test_state, &icache());
1079 assert_eq!(*test_state.bool_stack.get(0).unwrap(), true);
1080 }
1081
1082 #[test]
1083 fn code_pop_removes_top_element() {
1084 let mut test_state = PushState::new();
1085 test_state.code_stack.push(Item::int(1));
1086 test_state.code_stack.push(Item::int(2));
1087 test_state.code_stack.push(Item::int(3));
1088 code_pop(&mut test_state, &icache());
1089 assert_eq!(
1090 test_state.code_stack.to_string(),
1091 "2 1"
1092 );
1093 }
1094
1095 #[test]
1096 fn code_position_pushes_value_when_contained() {
1097 let mut test_state = PushState::new();
1098 test_state.code_stack.push(Item::int(3));
1099 test_state.code_stack.push(Item::list(vec![
1100 Item::int(4),
1101 Item::list(vec![Item::int(3)]),
1102 Item::int(2),
1103 Item::int(1),
1104 ]));
1105 code_position(&mut test_state, &icache());
1106 assert_eq!(test_state.int_stack.get(0).unwrap(), &4);
1107 }
1108
1109 #[test]
1110 fn code_print_creates_parseable_output() {
1111 let mut test_state = PushState::new();
1112 let mut instruction_set = InstructionSet::new();
1113 instruction_set.load();
1114 test_state.code_stack.push(Item::int(3));
1115 test_state.code_stack.push(Item::list(vec![
1116 Item::int(4),
1117 Item::list(vec![Item::int(3)]),
1118 Item::int(2),
1119 Item::int(1),
1120 ]));
1121 code_print(&mut test_state, &icache());
1122 assert_eq!(test_state.name_stack.size(), 1);
1123 let printed_code = test_state.name_stack.copy(0).unwrap();
1124 PushParser::parse_program(&mut test_state, &instruction_set, &printed_code);
1125 assert_eq!(
1126 test_state.exec_stack.to_string(), test_state.code_stack.to_string());
1127 }
1128
1129 #[test]
1130 fn code_quote_moves_item_from_exec_to_code_stack() {
1131 let mut test_state = PushState::new();
1132 test_state.exec_stack.push(Item::int(2));
1133 code_quote(&mut test_state, &icache());
1134 assert_eq!(test_state.code_stack.to_string(), "2")
1135 }
1136
1137 #[test]
1138 fn code_rand_pushes_random_code() {
1139 let mut test_state = PushState::new();
1140 test_state.int_stack.push(100);
1141 code_rand(&mut test_state, &icache());
1142 assert_eq!(test_state.code_stack.size(), 1);
1143 }
1144
1145 #[test]
1146 fn code_rot_shuffles_elements() {
1147 let mut test_state = PushState::new();
1148 test_state.code_stack.push(Item::int(3));
1149 test_state.code_stack.push(Item::int(2));
1150 test_state.code_stack.push(Item::int(1));
1151 assert_eq!(
1152 test_state.code_stack.to_string(),
1153 "1 2 3"
1154 );
1155 code_rot(&mut test_state, &icache());
1156 assert_eq!(
1157 test_state.code_stack.to_string(),
1158 "3 1 2"
1159 );
1160 }
1161
1162 #[test]
1163 fn code_shove_inserts_at_right_position() {
1164 let mut test_state = PushState::new();
1165 test_state.code_stack.push(Item::int(4));
1166 test_state.code_stack.push(Item::int(3));
1167 test_state.code_stack.push(Item::int(2));
1168 test_state.code_stack.push(Item::int(1));
1169 assert_eq!(
1170 test_state.code_stack.to_string(),
1171 "1 2 3 4"
1172 );
1173 test_state.int_stack.push(2);
1174 code_shove(&mut test_state, &icache());
1175 assert_eq!(
1176 test_state.code_stack.to_string(),
1177 "2 3 1 4"
1178 );
1179 }
1180
1181 #[test]
1182 fn code_size_calculates_top_element() {
1183 let mut test_state = PushState::new();
1184 let test_item = Item::list(vec![
1185 Item::int(4),
1186 Item::list(vec![Item::int(3)]),
1187 Item::int(2),
1188 Item::int(1),
1189 ]);
1190 test_state.code_stack.push(test_item);
1191 code_size(&mut test_state, &icache());
1192 assert_eq!(test_state.int_stack.to_string(), "6");
1193 }
1194
1195 #[test]
1196 fn code_substitute_code_elements() {
1197 let mut test_state = PushState::new();
1198 let target_item = Item::list(vec![
1199 Item::list(vec![]),
1200 Item::list(vec![Item::int(3)]),
1201 Item::int(2),
1202 Item::int(1),
1203 ]);
1204 let substitute = Item::int(4);
1205 let pattern = Item::list(vec![]);
1206 test_state.code_stack.push(pattern);
1207 test_state.code_stack.push(substitute);
1208 test_state.code_stack.push(target_item);
1209 code_subst(&mut test_state, &icache());
1210 assert_eq!(
1211 test_state.code_stack.to_string(),
1212 "( 1 2 ( 3 ) 4 )"
1213 );
1214 }
1215
1216 #[test]
1217 fn code_swaps_top_elements() {
1218 let mut test_state = PushState::new();
1219 test_state.code_stack.push(Item::int(0));
1220 test_state.code_stack.push(Item::int(1));
1221 assert_eq!(
1222 test_state.code_stack.to_string(),
1223 "1 0"
1224 );
1225 code_swap(&mut test_state, &icache());
1226 assert_eq!(
1227 test_state.code_stack.to_string(),
1228 "0 1"
1229 );
1230 }
1231
1232 #[test]
1233 fn code_yank_brings_item_to_top() {
1234 let mut test_state = PushState::new();
1235 test_state.code_stack.push(Item::int(5));
1236 test_state.code_stack.push(Item::int(4));
1237 test_state.code_stack.push(Item::int(3));
1238 test_state.code_stack.push(Item::int(2));
1239 test_state.code_stack.push(Item::int(1));
1240 assert_eq!(
1241 test_state.code_stack.to_string(),
1242 "1 2 3 4 5"
1243 );
1244 test_state.int_stack.push(3);
1245 code_yank(&mut test_state, &icache());
1246 assert_eq!(
1247 test_state.code_stack.to_string(),
1248 "4 1 2 3 5"
1249 );
1250 }
1251
1252 #[test]
1253 fn code_yank_dup_copies_item_to_top() {
1254 let mut test_state = PushState::new();
1255 test_state.code_stack.push(Item::int(5));
1256 test_state.code_stack.push(Item::int(4));
1257 test_state.code_stack.push(Item::int(3));
1258 test_state.code_stack.push(Item::int(2));
1259 test_state.code_stack.push(Item::int(1));
1260 assert_eq!(
1261 test_state.code_stack.to_string(),
1262 "1 2 3 4 5"
1263 );
1264 test_state.int_stack.push(3);
1265 code_yank_dup(&mut test_state, &icache());
1266 assert_eq!(
1267 test_state.code_stack.to_string(),
1268 "4 1 2 3 4 5"
1269 );
1270 }
1271}