hrm_interpreter/operators/
add.rs

1use operators::Operator;
2use Value;
3use Location;
4use state;
5use memory;
6// --
7use 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}