hrm_interpreter 0.2.0

a small interpreter for the HRM language, used in Human Resource Machine
Documentation
use Value;
use Operation;
use operators;
use operators::Operator;

#[derive(Serialize, Debug, Clone)]
pub struct InternalState {
  pub register: Option<Value>,
	pub input_tape: Vec<Value>,
	pub output_tape: Vec<Value>,
	pub memory: Vec<Option<Value>>,
	pub instruction_counter: usize,
	_executed_instructions: u32
}


macro_rules! apply_operation {
	($self: ident, $operator:expr) => ({
		let op = $operator;
    match op.apply_to($self) {
			Ok(()) => {
				if !op.changes_instruction_counter() {
					$self.instruction_counter += 1;
				}
				$self.increase_executed_instructions();
				Ok(())
			},
			Err(reason) => {
				Err(reason)
			}
		}
	})
}

impl InternalState {
	pub fn new(register: Option<Value>, counter: usize) -> InternalState {
		InternalState {
			register,
			input_tape: vec!(),
			output_tape: vec!(),
			memory: vec!(),
			instruction_counter: counter,
			_executed_instructions: 0
		}
	}

	pub fn with_input_tape(mut self, new_input_tape: Vec<Value>) -> Self {
		self.input_tape = new_input_tape;
		self
	}

	pub fn with_memory(mut self, new_memory: Vec<Option<Value>>) -> Self {
		self.memory = new_memory;
		self
	}

    pub fn executed_instructions(&self) -> u32 {
		self._executed_instructions
	}

	pub fn increase_executed_instructions(&mut self) {
		self._executed_instructions += 1;
	}

	pub fn apply(&mut self, op: Operation) -> Result<(), String> {
		match op {
			Operation::Add{cell: _cell} => {
				apply_operation!(self, operators::add::AddOp{cell: _cell})
			},
			Operation::Sub{cell: _cell} => {
				apply_operation!(self, operators::sub::SubOp{cell: _cell})
			},
			Operation::Inbox => {
				apply_operation!(self, operators::inbox::InboxOp{})
			},
			Operation::Outbox => {
				apply_operation!(self, operators::outbox::OutboxOp{})
			},
			Operation::CopyFrom{cell: _cell} => {
				apply_operation!(self, operators::copyfrom::CopyFromOp{cell: _cell})
			},
			Operation::CopyTo{cell: _cell} => {
				apply_operation!(self, operators::copyto::CopyToOp{cell: _cell})
			},
			Operation::Label => {
				apply_operation!(self, operators::jump::LabelOp)
			},
			Operation::Jump{next_operation: _next_op} => {
				apply_operation!(self, operators::jump::JumpOp{next_operation: _next_op})
			},
			Operation::JumpEqualsZero{next_operation: _next_op} => {
				apply_operation!(self, operators::jump::JumpEqualsZeroOp{next_operation: _next_op})
			}
			Operation::JumpNegative{next_operation: _next_op} => {
				apply_operation!(self, operators::jump::JumpNegativeOp{next_operation: _next_op})
			}
			Operation::BumpPlus{cell: _cell} => {
				apply_operation!(self, operators::bump::BumpPlusOp{cell: _cell})
			}
			Operation::BumpMinus{cell: _cell} => {
				apply_operation!(self, operators::bump::BumpMinusOp{cell: _cell})
			}
		}
	}
}

#[cfg(test)]
mod test {
	use state::InternalState;
	use Value;
	use Operation;

	#[test]
	fn executed_counter_at_start() {
		let state = InternalState::new(None, 0);

		assert_eq!(state.executed_instructions(), 0);
	}

	#[test]
	fn executed_counter_is_increased() {
		let mut state = InternalState::new(None, 0)
			.with_input_tape(vec!(Value::Number{value: 1}));

		let _ = state.apply(Operation::Inbox);

		assert_eq!(state.executed_instructions(), 1);
	}
}