Решение на Reversible Interpreter от Георги Анастасов
Към профила на Георги Анастасов
Резултати
- 14 точки от тестове
- 0 бонус точки
- 14 точки общо
- 11 успешни тест(а)
- 1 неуспешни тест(а)
Код
#[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>,
finished_instructions: Vec<String>,
reverce_numbers: Vec<i32>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::<String>::new(),
stack: Vec::<i32>::new(),
finished_instructions: Vec::<String>::new(),
reverce_numbers: Vec::<i32>::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> {
if self.instructions.is_empty() {
return Err(RuntimeError::NoInstructions);
}
let instruction = self.instructions.front().unwrap();
let split_instruction: Vec<&str> = instruction.split_whitespace().collect();
let instruction_size = split_instruction.len();
if instruction_size > 2 {
return Err(RuntimeError::InvalidCommand);
} else if instruction_size == 2 {
let value = match split_instruction[1].parse::<i32>() {
Ok(number) => number,
Err(_) => return Err(RuntimeError::InvalidCommand),
};
match split_instruction[0] {
"PUSH" => self.stack.push(value),
_ => return Err(RuntimeError::InvalidCommand),
}
} else {
match split_instruction[0] {
"POP" => match self.stack.pop() {
Some(_) => (),
None => return Err(RuntimeError::StackUnderflow),
},
"ADD" => {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let first = self.stack.pop().unwrap();
let second = self.stack.pop().unwrap();
self.reverce_numbers.push(first);
self.reverce_numbers.push(second);
self.stack.push(first + second);
}
"MUL" => {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let first = self.stack.pop().unwrap();
let second = self.stack.pop().unwrap();
self.stack.push(first * second);
}
"SUB" => {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let first = self.stack.pop().unwrap();
let second = self.stack.pop().unwrap();
self.reverce_numbers.push(first);
self.reverce_numbers.push(second);
self.stack.push(first - second);
}
"DIV" => {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let first = self.stack.pop().unwrap();
let second = self.stack.pop().unwrap();
if second == 0 {
return Err(RuntimeError::DivideByZero);
}
self.reverce_numbers.push(first);
self.reverce_numbers.push(second);
self.stack.push(first / second);
}
_ => return Err(RuntimeError::InvalidCommand),
}
}
self.finished_instructions
.push(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),
_ => (),
}
}
}
pub fn back(&mut self) -> Result<(), RuntimeError> {
if self.finished_instructions.is_empty() {
return Err(RuntimeError::NoInstructions);
}
let instruction = self.finished_instructions.pop().unwrap();
let split_instruction: Vec<&str> = instruction.split_whitespace().collect();
let instruction_size = split_instruction.len();
if instruction_size == 2 {
self.stack.pop();
} else {
match split_instruction[0] {
"POP" => self.stack.push(self.reverce_numbers.pop().unwrap()),
"ADD" => {
self.stack.pop();
self.stack.push(self.reverce_numbers.pop().unwrap());
self.stack.push(self.reverce_numbers.pop().unwrap());
}
"MUL" => {
self.stack.pop();
self.stack.push(self.reverce_numbers.pop().unwrap());
self.stack.push(self.reverce_numbers.pop().unwrap());
}
"SUB" => {
self.stack.pop();
self.stack.push(self.reverce_numbers.pop().unwrap());
self.stack.push(self.reverce_numbers.pop().unwrap());
}
"DIV" => {
self.stack.pop();
self.stack.push(self.reverce_numbers.pop().unwrap());
self.stack.push(self.reverce_numbers.pop().unwrap());
}
_ => return Err(RuntimeError::InvalidCommand),
}
}
self.instructions.push_front(instruction);
Ok(())
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-ljjsv8/solution) Finished test [unoptimized + debuginfo] target(s) in 2.42s Running target/debug/deps/solution_test-8916805fc40a2dab running 12 tests test solution_test::test_arg_number ... ok test solution_test::test_arithmetic_back ... FAILED 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 failures: ---- solution_test::test_arithmetic_back stdout ---- thread 'main' panicked at 'assertion failed: `(left == right)` left: `[1, 2]`, right: `[3, 3]`', tests/solution_test.rs:113:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: solution_test::test_arithmetic_back test result: FAILED. 11 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out error: test failed, to rerun pass '--test solution_test'