Решение на 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>,
back_info: VecDeque<String>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {instructions:VecDeque::new(), stack: Vec::new(), back_info: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> {
if self.current_instruction().is_none() == true {
return Err(RuntimeError::NoInstructions);
} else {
let curr_instruction = self.current_instruction().unwrap().clone();
let instruction_pieces:Vec<&str> = curr_instruction.split_whitespace().collect();
match instruction_pieces[0] {
"PUSH" => {
if instruction_pieces.len() != 2 {
return Err(RuntimeError::InvalidCommand)
}
if instruction_pieces[1].parse::<i32>().is_err() == true {
return Err(RuntimeError::InvalidCommand);
} else {
self.stack.push(instruction_pieces[1].clone().parse::<i32>().unwrap());
self.back_info.push_back(curr_instruction);
self.instructions.pop_front();
return Ok(());
}
},
"POP" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
} else {
self.stack.pop();
self.back_info.push_back(curr_instruction);
self.instructions.pop_front();
return Ok(());
}
},
"ADD" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let top1=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let top2=self.stack.pop();
self.stack.push(top1.unwrap()+top2.unwrap());
self.back_info.push_back(curr_instruction);
self.instructions.pop_front();
return Ok(());
}
},
"MUL" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let top1=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let top2=self.stack.pop();
self.stack.push(top1.unwrap()*top2.unwrap());
self.back_info.push_back(curr_instruction);
self.instructions.pop_front();
return Ok(());
}
},
"SUB" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let x=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let y=self.stack.pop();
self.stack.push(x.unwrap()-y.unwrap());
self.back_info.push_back(curr_instruction);
self.instructions.pop_front();
return Ok(());
}
},
"DIV" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let x=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let y=self.stack.pop();
if y.unwrap() == 0 {return Err(RuntimeError::DivideByZero);}
self.stack.push(x.unwrap()/y.unwrap());
self.back_info.push_back(curr_instruction);
self.instructions.pop_front();
return Ok(());
}
},
_ => Err(RuntimeError::InvalidCommand)
}
}
}
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.back_info.len() != 0 {
self.stack = Vec::new();
self.instructions.push_front(self.back_info.pop_back().unwrap().clone());
let helper_instructions = self.instructions.clone();
self.instructions = self.back_info.clone();
for _instruction in self.instructions.clone() {
if self.current_instruction().is_none() == true {
return Err(RuntimeError::NoInstructions);
} else {
let curr_instruction = self.current_instruction().unwrap().clone();
let instruction_pieces:Vec<&str> = curr_instruction.split_whitespace().collect();
match instruction_pieces[0] {
"PUSH" => {
if instruction_pieces.len() != 2 {
return Err(RuntimeError::InvalidCommand)
}
if instruction_pieces[1].parse::<i32>().is_err() == true {
return Err(RuntimeError::InvalidCommand);
} else {
self.stack.push(instruction_pieces[1].clone().parse::<i32>().unwrap());
self.instructions.pop_front();
}
},
"POP" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
} else {
self.stack.pop();
self.instructions.pop_front();
}
},
"ADD" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let top1=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let top2=self.stack.pop();
self.stack.push(top1.unwrap()+top2.unwrap());
self.instructions.pop_front();
}
},
"MUL" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let top1=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let top2=self.stack.pop();
self.stack.push(top1.unwrap()*top2.unwrap());
self.instructions.pop_front();
}
},
"SUB" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let x=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let y=self.stack.pop();
self.stack.push(x.unwrap()-y.unwrap());
self.instructions.pop_front();
}
},
"DIV" => {
if instruction_pieces.len() != 1 {
return Err(RuntimeError::InvalidCommand)
}
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}else{
let x=self.stack.pop();
if self.stack.is_empty() == true {
return Err(RuntimeError::StackUnderflow);
}
let y=self.stack.pop();
if y.unwrap() == 0 {return Err(RuntimeError::DivideByZero);}
self.stack.push(x.unwrap()/y.unwrap());
self.instructions.pop_front();
}
},
_ => unreachable!()
}
}}
self.instructions = helper_instructions;
return Ok(());
}else {
return Err(RuntimeError::NoInstructions);
}
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-x6lexy/solution) Finished test [unoptimized + debuginfo] target(s) in 2.56s 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