Решение на 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>,
undo_stack: Vec<UndoOP>,
}
#[derive(Debug)]
struct UndoOP {
instruction: String,
to_push: Vec<i32>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::new(),
stack: Vec::new(),
undo_stack: Vec::new(),
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for i in instructions.iter() {
self.instructions.push_back(i.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let instruction = match self.instructions.front() {
None => return Err(RuntimeError::NoInstructions),
Some(instruction) => instruction,
};
let mut instruction_iter = instruction.split_whitespace();
let instruction = instruction_iter.next().unwrap();
let mut to_push = Vec::new();
match instruction {
"PUSH" => match instruction_iter.next() {
None => return Err(RuntimeError::InvalidCommand),
Some(x) => match x.parse::<i32>() {
Err(_) => return Err(RuntimeError::InvalidCommand),
Ok(x) => match instruction_iter.next() {
Some(_) => return Err(RuntimeError::InvalidCommand),
None => {
to_push.push(x);
self.stack.push(x);
}
},
},
},
"POP" => match instruction_iter.next() {
None => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => to_push.push(x),
},
Some(_) => return Err(RuntimeError::InvalidCommand),
},
"ADD" => match instruction_iter.next() {
None => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(a) => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(b) => {
to_push.push(a);
to_push.push(b);
self.stack.push(a + b)
}
},
},
Some(_) => return Err(RuntimeError::InvalidCommand),
},
"MUL" => match instruction_iter.next() {
None => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(a) => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(b) => {
to_push.push(a);
to_push.push(b);
self.stack.push(a * b)
}
},
},
Some(_) => return Err(RuntimeError::InvalidCommand),
},
"SUB" => match instruction_iter.next() {
None => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(a) => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(b) => {
to_push.push(a);
to_push.push(b);
self.stack.push(a - b)
}
},
},
Some(_) => return Err(RuntimeError::InvalidCommand),
},
"DIV" => match instruction_iter.next() {
None => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(a) => match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(0) => return Err(RuntimeError::DivideByZero),
Some(b) => {
to_push.push(a);
to_push.push(b);
self.stack.push(a / b)
}
},
},
Some(_) => return Err(RuntimeError::InvalidCommand),
},
_ => return Err(RuntimeError::InvalidCommand),
};
let undo_operation = self.instructions.pop_front();
self.undo_stack.push(UndoOP {
instruction: undo_operation.unwrap(),
to_push,
});
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> {
let mut operation = match self.undo_stack.pop() {
None => return Err(RuntimeError::NoInstructions),
Some(x) => x,
};
let instruction = operation.instruction.split_whitespace().next().unwrap();
match instruction {
"PUSH" => {
self.stack.pop();
}
"POP" => self.stack.push(operation.to_push.pop().unwrap()),
"ADD" | "MUL" | "SUB" | "DIV" => {
self.stack.pop();
self.stack.push(operation.to_push.pop().unwrap());
self.stack.push(operation.to_push.pop().unwrap());
}
_ => unreachable!(),
}
self.instructions.push_front(operation.instruction);
Ok(())
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-qev88n/solution)
    Finished test [unoptimized + debuginfo] target(s) in 2.55s
     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 коментара)

Биляна качи първо решение на 19.01.2021 00:49 (преди над 4 години)