Решение на Reversible Interpreter от Борис Петров
Резултати
- 15 точки от тестове
- 0 бонус точки
- 15 точки общо
- 12 успешни тест(а)
- 0 неуспешни тест(а)
Код
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
use std::collections::VecDeque;
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
pub reverse_instructions: VecDeque<String>,
pub history_instructions: VecDeque<String>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::new(),
stack: Vec::new(),
reverse_instructions: VecDeque::new(),
history_instructions: VecDeque::new(),
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instruction in instructions {
self.instructions.push_back(instruction.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
match self.instructions.front() {
None => Err(RuntimeError::NoInstructions),
Some(instruction) => {
match instruction
.clone()
.split_whitespace()
.collect::<Vec<&str>>()
{
iter if iter[0] == "POP" => {
if iter.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() < 1 {
return Err(RuntimeError::StackUnderflow);
}
let val = self.stack.pop().unwrap().to_string();
self.reverse_instructions
.push_front("PUSH ".to_string() + &val);
()
}
iter if iter[0] == "ADD" => {
if iter.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let val1 = self.stack.pop().unwrap();
let val2 = self.stack.pop().unwrap();
let sum = val1 + val2;
self.stack.push(sum);
self.reverse_instructions
.push_front("PUSH ".to_string() + &val1.to_string());
self.reverse_instructions
.push_front("PUSH ".to_string() + &val2.to_string());
self.reverse_instructions.push_front("POP".to_string());
()
}
iter if iter[0] == "MUL" => {
if iter.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let val1 = self.stack.pop().unwrap();
let val2 = self.stack.pop().unwrap();
let result = val1 * val2;
self.stack.push(result);
self.reverse_instructions
.push_front("PUSH ".to_string() + &val1.to_string());
self.reverse_instructions
.push_front("PUSH ".to_string() + &val2.to_string());
self.reverse_instructions.push_front("POP".to_string());
()
}
iter if iter[0] == "SUB" => {
if iter.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let val1 = self.stack.pop().unwrap();
let val2 = self.stack.pop().unwrap();
let result = val1 - val2;
self.stack.push(result);
self.reverse_instructions
.push_front("PUSH ".to_string() + &val1.to_string());
self.reverse_instructions
.push_front("PUSH ".to_string() + &val2.to_string());
self.reverse_instructions.push_front("POP".to_string());
()
}
iter if iter[0] == "DIV" => {
if iter.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let val1 = self.stack.pop().unwrap();
let val2 = self.stack.pop().unwrap();
if val2 == 0 {
self.stack.push(val2);
self.stack.push(val1);
return Err(RuntimeError::DivideByZero);
}
let result = val1 / val2;
self.stack.push(result);
self.reverse_instructions
.push_front("PUSH ".to_string() + &val1.to_string());
self.reverse_instructions
.push_front("PUSH ".to_string() + &val2.to_string());
self.reverse_instructions.push_front("POP".to_string());
()
}
iter if iter[0] == "PUSH" => {
if iter.len() != 2 {
return Err(RuntimeError::InvalidCommand);
}
self.stack.push(iter[1].parse().unwrap());
self.reverse_instructions.push_front("POP".to_string());
()
}
_ => return Err(RuntimeError::InvalidCommand),
}
self.history_instructions
.push_front(self.instructions.pop_front().unwrap());
Ok(())
}
}
}
pub fn run(&mut self) -> Result<(), RuntimeError> {
loop {
match self.forward() {
Err(RuntimeError::NoInstructions) => return Ok(()),
Err(e) => return Err(e),
_ => (),
}
}
}
fn reverse(&mut self) -> Result<(), RuntimeError> {
match self.reverse_instructions.pop_front() {
None => Err(RuntimeError::NoInstructions),
Some(instruction) => {
match instruction
.clone()
.split_whitespace()
.collect::<Vec<&str>>()
{
iter if iter[0] == "POP" => {
if iter.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() < 1 {
return Err(RuntimeError::StackUnderflow);
}
self.stack.pop().unwrap().to_string();
Ok(())
}
iter if iter[0] == "PUSH" => {
if iter.len() != 2 {
return Err(RuntimeError::InvalidCommand);
}
self.stack.push(iter[1].parse().unwrap());
Ok(())
}
_ => Err(RuntimeError::InvalidCommand),
}
}
}
}
pub fn back(&mut self) -> Result<(), RuntimeError> {
match self.history_instructions.pop_front() {
None => Err(RuntimeError::NoInstructions),
Some(instruction) => {
self.instructions.push_front(instruction.clone());
match instruction
.clone()
.split_whitespace()
.collect::<Vec<&str>>()
{
iter if iter[0] == "POP" || iter[0] == "PUSH" => self.reverse(),
iter if iter[0] == "ADD"
|| iter[0] == "MUL"
|| iter[0] == "SUB"
|| iter[0] == "DIV" =>
{
match self.reverse() {
Err(e) => Err(e),
Ok(()) => match self.reverse() {
Err(e) => Err(e),
Ok(()) => self.reverse(),
},
}
}
_ => Err(RuntimeError::InvalidCommand),
}
}
}
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-16xz15/solution) Finished test [unoptimized + debuginfo] target(s) in 2.41s Running target/debug/deps/solution_test-8916805fc40a2dab running 12 tests test solution_test::test_arg_number ... ok test solution_test::test_arithmetic_back ... ok test solution_test::test_arithmetic_basic ... ok test solution_test::test_div_1 ... ok test solution_test::test_div_2 ... ok test solution_test::test_errors_1 ... ok test solution_test::test_errors_2 ... ok test solution_test::test_instructions_after_error ... ok test solution_test::test_invalid_args ... ok test solution_test::test_pop ... ok test solution_test::test_push ... ok test solution_test::test_restoring_instructions ... ok test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out