Решение на 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>,
reverse_instructions: Vec<String>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::<String>::new(),
stack: Vec::<i32>::new(),
reverse_instructions: Vec::<String>::new()
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for elem in instructions {
self.instructions.push_back(elem.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let current = self.instructions.pop_front();
if current == None {
Err(RuntimeError::NoInstructions)
}
else {
let unwrapped_current = current.unwrap();
let mut command_split = unwrapped_current.split_whitespace();
match command_split.next().unwrap().to_uppercase().as_str() {
"PUSH" => self.push(&mut command_split),
"POP" => self.pop(&mut command_split),
"ADD" => self.add(&mut command_split),
"SUB" => self.sub(&mut command_split),
"MUL" => self.mul(&mut command_split),
"DIV" => self.div(&mut command_split),
_ => Err(RuntimeError::InvalidCommand)
}
}
}
fn push(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let mut number_as_str = other_instruction.next();
if number_as_str == None {
self.return_failed_instruction("PUSH".to_string(), "", other_instruction);
return Err(RuntimeError::InvalidCommand);
}
let copy_as_str = number_as_str.clone();
let number = number_as_str.unwrap().parse::<i32>();
number_as_str = other_instruction.next();
if number_as_str != None {
self.return_failed_instruction(
"PUSH".to_string(),
&format!(" {} {}", copy_as_str.unwrap(), number_as_str.unwrap()),
other_instruction);
return Err(RuntimeError::InvalidCommand);
}
match number {
Ok(x) => {
self.stack.push(x);
self.reverse_instructions.push(format!("{}", "POP"));
Ok(())
},
_ => {
self.return_failed_instruction(
"PUSH".to_string(),
&format!(" {}", copy_as_str.unwrap()),
other_instruction);
Err(RuntimeError::InvalidCommand)
}
}
}
fn pop(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let more = other_instruction.next();
if more != None {
self.return_failed_instruction("POP".to_string(), &format!(" {}", more.unwrap()), other_instruction);
return Err(RuntimeError::InvalidCommand);
}
let current = self.stack.pop();
match current {
None => {
self.return_failed_instruction("POP".to_string(), "", other_instruction);
Err(RuntimeError::StackUnderflow)
},
Some(x) => {
self.reverse_instructions.push(format!("{} {}", "PUSH", x.to_string()));
Ok(())
}
}
}
fn add(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let more = other_instruction.next();
if more != None {
self.return_failed_instruction("ADD".to_string(), &format!(" {}", more.unwrap()), other_instruction);
return Err(RuntimeError::InvalidCommand);
}
let left = self.stack.pop();
let mut left_as_i32: i32;
match left{
Some(x) => left_as_i32 = x,
None => {
self.return_failed_instruction("ADD".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
let right = self.stack.pop();
match right {
Some(x) => {
self.stack.push(left_as_i32 + x);
self.reverse_instructions.push(format!("{} {}", "SUB", x.to_string()));
Ok(())
},
None => {
self.stack.push(left_as_i32);
self.return_failed_instruction("ADD".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
}
fn sub(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let more = other_instruction.next();
if more != None {
self.return_failed_instruction("SUB".to_string(), &format!(" {}", more.unwrap()), other_instruction);
return Err(RuntimeError::InvalidCommand);
}
let left = self.stack.pop();
let mut left_as_i32: i32;
match left{
Some(x) => left_as_i32 = x,
None => {
self.return_failed_instruction("SUB".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
let right = self.stack.pop();
match right {
Some(x) => {
self.stack.push(left_as_i32 - x);
self.reverse_instructions.push(format!("{} {}", "ADD", x.to_string()));
Ok(())
},
None => {
self.stack.push(left_as_i32);
self.return_failed_instruction("SUB".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
}
fn mul(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let more = other_instruction.next();
if more != None {
self.return_failed_instruction("MUL".to_string(), &format!(" {}", more.unwrap()), other_instruction);
return Err(RuntimeError::InvalidCommand);
}
let left = self.stack.pop();
let mut left_as_i32: i32;
match left{
Some(x) => left_as_i32 = x,
None => {
self.return_failed_instruction("MUL".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
let right = self.stack.pop();
match right {
Some(x) => {
self.stack.push(left_as_i32 * x);
self.reverse_instructions.push(format!("{} {}", "DIV", x.to_string()));
Ok(())
},
None => {
self.stack.push(left_as_i32);
self.return_failed_instruction("MUL".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
}
fn div(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let more = other_instruction.next();
if more != None {
self.return_failed_instruction("DIV".to_string(), &format!(" {}", more.unwrap()), other_instruction);
return Err(RuntimeError::InvalidCommand);
}
let left = self.stack.pop();
let mut left_as_i32: i32;
match left{
Some(x) => left_as_i32 = x,
None => {
self.return_failed_instruction("DIV".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
let right = self.stack.pop();
match right {
Some(x) => {
if x == 0 {
self.stack.push(x);
self.stack.push(left_as_i32);
self.return_failed_instruction("DIV".to_string(), "", other_instruction);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(left_as_i32 / x);
self.reverse_instructions.push(format!("{} {}", "MUL", x.to_string()));
Ok(())
},
None => {
self.stack.push(left_as_i32);
self.return_failed_instruction("DIV".to_string(), "", other_instruction);
return Err(RuntimeError::StackUnderflow)
}
}
}
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> {
let current = self.reverse_instructions.pop();
if current == None {
Err(RuntimeError::NoInstructions)
}
else {
let unwrapped_current = current.unwrap();
let mut command_split = unwrapped_current.split_whitespace();
match command_split.next().unwrap().to_uppercase().as_str() {
"PUSH" => self.push_rev(&mut command_split),
"POP" => self.pop_rev(),
"ADD" => self.add_rev(&mut command_split),
"SUB" => self.sub_rev(&mut command_split),
"MUL" => self.mul_rev(&mut command_split),
"DIV" => self.div_rev(&mut command_split),
_ => Err(RuntimeError::InvalidCommand)
}
}
}
fn push_rev(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let mut number: i32 = other_instruction.next().unwrap().parse().unwrap();
self.stack.push(number);
self.instructions.push_front("POP".to_string());
Ok(())
}
fn pop_rev(&mut self) -> Result<(), RuntimeError> {
let current: i32 = self.stack.pop().unwrap();
self.instructions.push_front(format!("{} {}", "PUSH", current.to_string()));
Ok(())
}
fn add_rev(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let right_as_i32: i32 = other_instruction.next().unwrap().parse().unwrap();
let sum_as_i32 = self.stack.pop().unwrap();
let left = sum_as_i32 + right_as_i32;
self.stack.push(right_as_i32);
self.stack.push(left);
self.instructions.push_front("SUB".to_string());
Ok(())
}
fn sub_rev(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let right_as_i32: i32 = other_instruction.next().unwrap().parse().unwrap();
let sum_as_i32 = self.stack.pop().unwrap();
let left = sum_as_i32 - right_as_i32;
self.stack.push(right_as_i32);
self.stack.push(left);
self.instructions.push_front("ADD".to_string());
Ok(())
}
fn mul_rev(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let right_as_i32: i32 = other_instruction.next().unwrap().parse().unwrap();
let product_as_i32 = self.stack.pop().unwrap();
let left = product_as_i32 * right_as_i32;
self.stack.push(right_as_i32);
self.stack.push(left);
self.instructions.push_front("DIV".to_string());
Ok(())
}
fn div_rev(&mut self, other_instruction: &mut std::str::SplitWhitespace) -> Result<(), RuntimeError> {
let right_as_i32: i32 = other_instruction.next().unwrap().parse().unwrap();
let product_as_i32 = self.stack.pop().unwrap();
let left = product_as_i32 / right_as_i32;
self.stack.push(right_as_i32);
self.stack.push(left);
self.instructions.push_front("MUL".to_string());
Ok(())
}
fn return_failed_instruction(&mut self, op: String, first: &str, other_instruction: &mut std::str::SplitWhitespace) {
let mut output = op + first;
let mut current;
loop{
current = other_instruction.next();
if current == None{
break;
}
output += current.unwrap();
}
self.instructions.push_front(output);
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-13qc5ct/solution) warning: variable does not need to be mutable --> src/lib.rs:118:13 | 118 | let mut left_as_i32: i32; | ----^^^^^^^^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable does not need to be mutable --> src/lib.rs:150:13 | 150 | let mut left_as_i32: i32; | ----^^^^^^^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:182:13 | 182 | let mut left_as_i32: i32; | ----^^^^^^^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:214:13 | 214 | let mut left_as_i32: i32; | ----^^^^^^^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:275:13 | 275 | let mut number: i32 = other_instruction.next().unwrap().parse().unwrap(); | ----^^^^^^ | | | help: remove this `mut` warning: 5 warnings emitted Finished test [unoptimized + debuginfo] target(s) in 2.45s 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 ... FAILED 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_div_2 stdout ---- thread 'main' panicked at 'assertion failed: `(left == right)` left: `[5, 5]`, right: `[5, 7]`', tests/solution_test.rs:152:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: solution_test::test_div_2 test result: FAILED. 11 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out error: test failed, to rerun pass '--test solution_test'