Решение на Reversible Interpreter от Иван Лучев

Обратно към всички решения

Към профила на Иван Лучев

Резултати

  • 15 точки от тестове
  • 0 бонус точки
  • 15 точки общо
  • 12 успешни тест(а)
  • 0 неуспешни тест(а)

Код

use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
back_instructions: Vec<(String, Vec<String>)>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::new(),
stack: Vec::new(),
back_instructions: Vec::new(),
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
self.instructions.extend(instructions.iter().map(|x| x.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.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let args = self.instructions[0].split_whitespace().map(|x| x.to_string()).collect::<Vec<_>>();
let execution_result = self.execute(args, true);
if let Ok(_) = execution_result {
self.instructions.pop_front();
Ok(())
} else {
execution_result
}
}
fn execute(&mut self, args: Vec<String>, backup: bool) -> Result<(), RuntimeError> {
if args.len() == 0 {
return Err(RuntimeError::InvalidCommand);
}
match args[0].as_str() {
"PUSH" => self.execute_push(args, backup),
"POP" => self.execute_pop(args, backup),
"ADD" => self.execute_add(args, backup),
"SUB" => self.execute_sub(args, backup),
"MUL" => self.execute_mul(args, backup),
"DIV" => self.execute_div(args, backup),
_ => Err(RuntimeError::InvalidCommand),
}
}
fn execute_push(&mut self, instruction: Vec<String>, save_back: bool) -> Result<(), RuntimeError> {
if instruction.len() != 2 {
return Err(RuntimeError::InvalidCommand);
}
if let Ok(x) = instruction[1].parse::<i32>() {
self.stack.push(x);
if save_back {
self.back_instructions.push((instruction.join(" "), vec!["POP".to_string()]));
}
Ok(())
} else {
Err(RuntimeError::InvalidCommand)
}
}
fn execute_pop(&mut self, instruction: Vec<String>, save_back: bool) -> Result<(), RuntimeError> {
if instruction.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() != 0 {
let old_val = self.stack.pop().unwrap();
if save_back {
self.back_instructions.push((instruction.join(" "), vec![format!("PUSH {}", old_val)]));
}
Ok(())
} else{
Err(RuntimeError::StackUnderflow)
}
}
fn execute_add(&mut self, instruction: Vec<String>, save_back: bool) -> Result<(), RuntimeError> {
if instruction.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() >= 2 {
let old_val_1 = self.stack.pop().unwrap();
let old_val_2 = self.stack.pop().unwrap();
let result = old_val_1 + old_val_2;
self.stack.push(result);
if save_back {
self.back_instructions.push((instruction.join(" "), vec!["POP".to_string(), format!("PUSH {}", old_val_2), format!("PUSH {}", old_val_1)]));
}
Ok(())
} else{
Err(RuntimeError::StackUnderflow)
}
}
fn execute_sub(&mut self, instruction: Vec<String>, save_back: bool) -> Result<(), RuntimeError> {
if instruction.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() >= 2 {
let old_val_1 = self.stack.pop().unwrap();
let old_val_2 = self.stack.pop().unwrap();
let result = old_val_1 - old_val_2;
self.stack.push(result);
if save_back {
self.back_instructions.push((instruction.join(" "), vec!["POP".to_string(), format!("PUSH {}", old_val_2), format!("PUSH {}", old_val_1)]));
}
Ok(())
} else{
Err(RuntimeError::StackUnderflow)
}
}
fn execute_mul(&mut self, instruction: Vec<String>, save_back: bool) -> Result<(), RuntimeError> {
if instruction.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() >= 2 {
let old_val_1 = self.stack.pop().unwrap();
let old_val_2 = self.stack.pop().unwrap();
let result = old_val_1 * old_val_2;
self.stack.push(result);
if save_back {
self.back_instructions.push((instruction.join(" "), vec!["POP".to_string(), format!("PUSH {}", old_val_2), format!("PUSH {}", old_val_1)]));
}
Ok(())
} else{
Err(RuntimeError::StackUnderflow)
}
}
fn execute_div(&mut self, instruction: Vec<String>, save_back: bool) -> Result<(), RuntimeError> {
if instruction.len() != 1 {
return Err(RuntimeError::InvalidCommand);
}
if self.stack.len() >= 2 {
let dividend = self.stack.pop().unwrap();
let divisor = self.stack.pop().unwrap();
if divisor == 0 {
return Err(RuntimeError::DivideByZero);
}
self.stack.push(dividend / divisor);
if save_back {
self.back_instructions.push((instruction.join(" "), vec!["POP".to_string(), format!("PUSH {}", divisor), format!("PUSH {}", dividend)]));
}
Ok(())
} else{
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> {
if self.back_instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let (old_instruction, reverse_last_instruction) = self.back_instructions.pop().unwrap();
self.instructions.push_front(old_instruction);
for instruction in reverse_last_instruction {
let _ = self.execute(instruction.split_whitespace().map(|x| x.to_string()).collect::<Vec<_>>(), false);
}
Ok(())
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20210120-1538662-1ddfv2b/solution)
    Finished test [unoptimized + debuginfo] target(s) in 2.59s
     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

История (1 версия и 0 коментара)

Иван качи първо решение на 15.01.2021 12:57 (преди 6 месеца)