1use crate::push::instructions::Instruction;
2use crate::push::instructions::InstructionCache;
3use crate::push::state::PushState;
4use crate::push::stack::PushPrint;
5use std::collections::HashMap;
6use std::fmt;
7
8#[derive(Clone, Debug)]
9pub struct Index {
10 pub current: usize,
11 pub destination: usize,
12}
13
14impl Index {
15 pub fn new(dest_arg: usize) -> Self {
16 Self {
17 current: 0,
18 destination: dest_arg,
19 }
20 }
21}
22
23impl PushPrint for Index {
24 fn to_pstring(&self) -> String {
25 format!("{}", self.to_string())
26 }
27}
28
29impl fmt::Display for Index {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 write!(f, "{}/{}", self.current, self.destination)
32 }
33}
34
35impl PartialEq for Index {
36 fn eq(&self, other: &Self) -> bool {
37 self.current == other.current && self.destination == other.destination
38 }
39}
40
41pub fn load_index_instructions(map: &mut HashMap<String, Instruction>) {
43 map.insert(
44 String::from("INDEX.CURRENT"),
45 Instruction::new(index_current),
46 );
47 map.insert(String::from("INDEX.DEFINE"), Instruction::new(index_define));
48 map.insert(
49 String::from("INDEX.DESTINATION"),
50 Instruction::new(index_destination),
51 );
52 map.insert(String::from("INDEX.FLUSH"), Instruction::new(index_flush));
53 map.insert(
54 String::from("INDEX.INCREASE"),
55 Instruction::new(index_increase),
56 );
57 map.insert(String::from("INDEX.POP"), Instruction::new(index_pop));
58}
59
60pub fn index_current(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
62 if let Some(index) = push_state.index_stack.copy(0) {
63 push_state.int_stack.push(index.current as i32);
64 }
65}
66
67pub fn index_define(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
69 if let Some(index) = push_state.int_stack.pop() {
70 let corr_index = i32::max(0, index);
71 push_state.index_stack.push(Index::new(corr_index as usize));
72 }
73}
74
75pub fn index_destination(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
77 if let Some(index) = push_state.index_stack.copy(0) {
78 push_state
79 .index_stack
80 .push(Index::new(index.destination as usize));
81 }
82}
83
84pub fn index_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
86 push_state.index_stack.flush();
87}
88
89pub fn index_increase(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
92 if let Some(index) = push_state.index_stack.get_mut(0) {
93 if index.current < index.destination {
94 index.current += 1;
95 }
96 }
97}
98
99pub fn index_pop(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
101 push_state.index_stack.pop();
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 pub fn icache() -> InstructionCache {
109 InstructionCache::new(vec![])
110 }
111
112
113 #[test]
114 fn integer_modulus_pushes_result() {
115 let mut test_state = PushState::new();
116 test_state.index_stack.push(Index::new(3));
117 index_increase(&mut test_state, &icache());
118 let mut test_index = Index::new(3);
119 test_index.current += 1;
120 assert_eq!(test_state.index_stack.pop().unwrap(), test_index);
121 }
122}