hrm_interpreter/operators/
add.rs1use operators::Operator;
2use Value;
3use Location;
4use state;
5use memory;
6use std::char;
8
9enum Error {
10 NoValue{cell: Location},
11 NoEmployeeValue,
12 SumOfChars,
13 SumOverflow{character: char, number: i32}
14}
15
16pub struct AddOp {
17 pub cell: Location
18}
19
20impl AddOp {
21 fn add_number_and_char(num: i32, c: char) -> Result<char, i32> {
22 const ALPHABET_RADIX: u32 = 36;
23 const SMALL_ASCII_A: i32 = 97;
24 const HEX_A_IN_DEC: i32 = 10;
25
26 let c_as_number = c.to_digit(ALPHABET_RADIX).unwrap() as i32;
27 let new_number = c_as_number + num;
28 let fixed_for_char: i32 = SMALL_ASCII_A + (new_number - HEX_A_IN_DEC);
29
30 if new_number < 0 || new_number >= 36 {
31 Err(new_number)
32 }
33 else {
34 Ok(char::from_u32(fixed_for_char as u32).unwrap())
35 }
36 }
37
38 fn explain_error(e: Error) -> String {
39 match e {
40 Error::NoValue{cell: Location::Cell(_cell)} => format!("There is no value at cell {:?}", _cell),
41 Error::NoValue{cell: Location::Address(_cell)} => format!("There is no value at cell {:?}", _cell),
42 Error::NoEmployeeValue => String::from("the Employee register holds no value. Cannot add."),
43 Error::SumOfChars => String::from("cannot sum two characters!"),
44 Error::SumOverflow{character: _char, number: _num} =>
45 format!("value overflowed! {} + {} is not representable as a letter!",
46 _char, _num)
47 }
48 }
49}
50
51impl Operator for AddOp {
52 fn changes_instruction_counter(&self) -> bool {
53 false
54 }
55
56 fn apply_to(&self, s: &mut state::InternalState) -> Result<(), String> {
57 let memory_position = memory::extract_memory_position(self.cell, &s);
58 if let Err(error) = memory_position {
59 return Err(memory::explain(error));
60 }
61
62 let value_from_memory = s.memory[memory_position.unwrap()].clone();
63 let res = match value_from_memory {
64 Some(ref v) => {
65 match s.register {
66 Some(old_register) => {
67 let new_register_value: Result<Value, String> = match (v, old_register) {
68 (&Value::Number{value: _v}, Value::Number{value: _old}) => {
69 Ok(Value::Number{value: _v + _old})
70 },
71 (&Value::Number{value: _v}, Value::Character{value: _old}) => {
72 if let Ok(new_char) = AddOp::add_number_and_char(_v, _old) {
73 Ok(Value::Character{value: new_char})
74 }
75 else {
76 Err(AddOp::explain_error(Error::SumOverflow{character: _old, number: _v}))
77 }
78 },
79 (&Value::Character{value: _v}, Value::Number{value: _old}) => {
80 if let Ok(new_char) = AddOp::add_number_and_char(_old, _v) {
81 Ok(Value::Character{value: new_char})
82 }
83 else {
84 Err(AddOp::explain_error(Error::SumOverflow{character: _v, number: _old}))
85 }
86 },
87 _ => Err(AddOp::explain_error(Error::SumOfChars))
88 };
89
90 match new_register_value {
91 Ok(value) => {
92 s.register = Some(value);
93 Ok(())
94 },
95 Err(reason) => Err(reason)
96 }
97 }
98 _ => {
99 Err(AddOp::explain_error(Error::NoEmployeeValue))
100 }
101 }
102 }
103 _ => {
104 Err(AddOp::explain_error(Error::NoValue{cell: self.cell}))
105 }
106 };
107
108 res
109 }
110}
111
112#[cfg(test)]
113mod test {
114 use state;
115 use Value;
116 use Location;
117 use Operation;
118 use operators::Operator;
119 use operators::add::AddOp;
120
121 #[test]
122 fn add_two_numbers(){
123 let mut state = state::InternalState::new(Some(Value::Number{value: 5}), 0)
124 .with_memory(vec!(Some(Value::Number{value: 4})));
125 let operation = AddOp{cell: Location::Cell(0)};
126
127 let _ = operation.apply_to(&mut state).unwrap();
128
129 assert!(match state.register {
130 Some(Value::Number{value: 9}) => true,
131 _ => false
132 });
133 }
134
135 #[test]
136 fn add_two_numbers_address() {
137 let mut state = state::InternalState::new(Some(Value::Number{value: 5}), 0);
138 state.memory = vec!(Some(Value::Number{value: 1}), Some(Value::Number{value: 4}));
139 let operation = AddOp{cell: Location::Address(0)};
140
141 let _ = operation.apply_to(&mut state).unwrap();
142
143 assert!(match state.register {
144 Some(Value::Number{value: 9}) => true,
145 _ => false
146 });
147 }
148
149 #[test]
150 fn add_number_to_empty_cell(){
151 let mut state = state::InternalState
152 ::new(Some(Value::Number{value: 5}), 0)
153 .with_memory(vec!(None));
154 let operation = AddOp{cell: Location::Cell(0)};
155
156 let result = operation.apply_to(& mut state);
157
158 assert!(result.is_err());
159 }
160
161 #[test]
162 fn add_two_numbers_to_empty_address() {
163 let mut state = state::InternalState::new(Some(Value::Number{value: 5}), 0);
164 state.memory = vec!(None, Some(Value::Number{value: 4}));
165 let operation = AddOp{cell: Location::Address(0)};
166
167 let result = operation.apply_to(&mut state);
168 assert!(result.is_err());
169 }
170
171 #[test]
172 fn add_number_to_empty_addressed_cell(){
173 let mut state = state::InternalState::new(Some(Value::Number{value: 5}), 0);
174 state.memory = vec!(Some(Value::Number{value: 1}), None, None, None, None);
175 let operation = AddOp{cell: Location::Address(0)};
176
177 let result = operation.apply_to(&mut state);
178 println!("{:?}", result);
179 assert!(result.is_err());
180 }
181
182 #[test]
183 fn add_number_to_empty_register(){
184 let mut state = state::InternalState
185 ::new(None, 0)
186 .with_memory(vec!(Some(Value::Number{value: 5})));
187 let operation = AddOp{cell: Location::Cell(0)};
188
189 let result = operation.apply_to(&mut state);
190
191 assert!(result.is_err());
192 }
193
194 #[test]
195 fn add_addressed_number_to_empty_register(){
196 let mut state = state::InternalState
197 ::new(None, 0)
198 .with_memory(vec!(Some(Value::Number{value: 1}), Some(Value::Number{value: 5})));
199 let operation = AddOp{cell: Location::Address(0)};
200
201 let result = operation.apply_to(&mut state);
202 assert!(result.is_err());
203 }
204
205 #[test]
206 fn add_char_to_char(){
207 let mut state = state::InternalState
208 ::new(Some(Value::Character{value: 'a'}), 0)
209 .with_memory(vec!(Some(Value::Character{value: 'a'})));
210 let operator = AddOp{cell: Location::Cell(0)};
211
212 let result = operator.apply_to(&mut state);
213
214 assert!(result.is_err());
215 }
216
217 #[test]
218 fn add_char_to_addressed_char(){
219 let mut state = state::InternalState::new(Some(Value::Character{value: 'a'}), 0);
220 state.memory = vec!(Some(Value::Number{value: 1}), Some(Value::Character{value: 'a'}));
221 let operator = AddOp{cell: Location::Address(0)};
222
223 let result = operator.apply_to(&mut state);
224
225 assert!(result.is_err());
226 }
227
228 #[test]
229 fn add_char_to_number(){
230 let mut state = state::InternalState
231 ::new(Some(Value::Character{value:'a'}), 0)
232 .with_memory(vec!(Some(Value::Number{value: 5})));
233 let _ = state.apply(Operation::Add{cell: Location::Cell(0)});
234
235 assert!(match state.register {
236 Some(Value::Character{value: 'f'}) => true,
237 _ => false
238 });
239 }
240
241 #[test]
242 fn add_char_to_number_overflow(){
243 let mut state = state::InternalState
244 ::new(Some(Value::Character{value:'z'}), 0)
245 .with_memory(vec!(Some(Value::Number{value: 5})));
246 let operation = AddOp{cell: Location::Cell(0)};
247
248 let result = operation.apply_to(&mut state);
249
250 assert!(result.is_err());
251 }
252
253 #[test]
254 fn add_number_to_char(){
255 let mut state = state::InternalState::new(Some(Value::Number{value:5}), 0)
256 .with_memory(vec!(Some(Value::Character{value: 'a'})));
257 let operation = AddOp{cell: Location::Cell(0)};
258
259 let _ = state.apply(Operation::Add{cell: Location::Cell(0)}).unwrap();
260
261 assert!(match state.register {
262 Some(Value::Character{value: 'f'}) => true,
263 _ => false
264 });
265 }
266
267 #[test]
268 fn add_number_to_addressed_char(){
269 let mut state = state::InternalState::new(Some(Value::Number{value: 5}), 0);
270 state.memory = vec!(Some(Value::Number{value: 1}), Some(Value::Character{value: 'a'}));
271
272 let _ = state.apply(Operation::Add{cell: Location::Address(0)}).unwrap();
273 assert!(match state.register {
274 Some(Value::Character{value: 'f'}) => true,
275 _ => false
276 });
277 }
278
279 #[test]
280 fn add_number_to_char_overflow(){
281 let mut state = state::InternalState::new(Some(Value::Number{value: 5}), 0)
282 .with_memory(vec!(Some(Value::Character{value: 'z'})));
283 let operation = AddOp{cell: Location::Cell(0)};
284
285 let result = operation.apply_to(&mut state);
286
287 assert!(result.is_err());
288 }
289}