Решение на Reversible Interpreter от Мартин Дацев

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

Към профила на Мартин Дацев

Резултати

  • 13 точки от тестове
  • 0 бонус точки
  • 13 точки общо
  • 10 успешни тест(а)
  • 2 неуспешни тест(а)

Код

#[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_states: VecDeque<Interpreter>,
}
impl Interpreter {
pub fn new() -> Self {
return Interpreter{instructions: VecDeque::new(), stack: vec![], back_states: VecDeque::new()};
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instr in instructions {
self.instructions.push_back(instr.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.get_mut(0)
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
if let Some(instr) = self.current_instruction() {
let instr = instr.clone();
self.back_states.push_back(Interpreter{instructions: self.instructions.clone(), stack: self.stack.clone(), back_states: VecDeque::new()});
let args : Vec<&str> = instr.split_whitespace().collect();
match args[0] {
"PUSH" => {
if args.len() != 2 { return Err(RuntimeError::InvalidCommand) }
self.stack.push(str::parse::<i32>(args[1]).map_err(|_| RuntimeError::InvalidCommand)?);
},
"POP" => {
if args.len() != 1 { return Err(RuntimeError::InvalidCommand) }
self.stack.pop();
},
"ADD" => {
if args.len() != 1 { return Err(RuntimeError::InvalidCommand) }
if self.stack.len() < 2 { return Err(RuntimeError::StackUnderflow) }
let sum = self.stack.pop().unwrap() + self.stack.pop().unwrap();
self.stack.push(sum);
},
"MUL" => {
if args.len() != 1 { return Err(RuntimeError::InvalidCommand) }
if self.stack.len() < 2 { return Err(RuntimeError::StackUnderflow) }
let sum = self.stack.pop().unwrap() * self.stack.pop().unwrap();
self.stack.push(sum);
},
"SUB" => {
if args.len() != 1 { return Err(RuntimeError::InvalidCommand) }
if self.stack.len() < 2 { return Err(RuntimeError::StackUnderflow) }
let sum = self.stack.pop().unwrap() - self.stack.pop().unwrap();
self.stack.push(sum);
},
"DIV" => {
if args.len() != 1 { return Err(RuntimeError::InvalidCommand) }
if self.stack.len() < 2 { return Err(RuntimeError::StackUnderflow) }
if self.stack[self.stack.len() - 2] == 0 { return Err(RuntimeError::DivideByZero) }
let sum = self.stack.pop().unwrap() / self.stack.pop().unwrap();
self.stack.push(sum);
},
_ => return Err(RuntimeError::InvalidCommand)
}
self.instructions.pop_front();
Ok(())
} else {
Err(RuntimeError::NoInstructions)
}
}
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 let Some(last_state) = self.back_states.pop_back() {
self.instructions = last_state.instructions;
self.stack = last_state.stack;
Ok(())
} else {
Err(RuntimeError::NoInstructions)
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-5hwzug/solution)
    Finished test [unoptimized + debuginfo] target(s) in 2.50s
     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 ... FAILED
test solution_test::test_errors_2 ... ok
test solution_test::test_instructions_after_error ... FAILED
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_errors_1 stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Ok(())`,
 right: `Err(StackUnderflow)`', tests/solution_test.rs:159:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- solution_test::test_instructions_after_error stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `["PUSH 2", "DIV", "PUSH 3"]`,
 right: `["PUSH 0", "PUSH 2", "DIV", "PUSH 3"]`', tests/solution_test.rs:219:5


failures:
    solution_test::test_errors_1
    solution_test::test_instructions_after_error

test result: FAILED. 10 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test solution_test'

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

Мартин качи първо решение на 20.01.2021 01:13 (преди над 4 години)