Решение на Reversible Interpreter от Бетина Христова

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

Към профила на Бетина Христова

Резултати

  • 11 точки от тестове
  • 0 бонус точки
  • 11 точки общо
  • 9 успешни тест(а)
  • 3 неуспешни тест(а)

Код

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>,
history_instructions: VecDeque<String>,
history_values: Vec<i32>
}
impl Interpreter {
pub fn new() -> Self {
return Interpreter {instructions: VecDeque::<String>::new(), stack: Vec::<i32>::new(),
history_instructions: VecDeque::<String>::new(), history_values: Vec::<i32>::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.front_mut()
}
pub fn remove_instruction(&mut self) {
self.instructions.pop_front();
}
pub fn add_to_history(&mut self, instruction: String, value: Option<i32>)
{
self.history_instructions.push_back(instruction);
if let Some(val) = value {
self.history_values.push(val);
}
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let curr_instr = self.current_instruction();
let mut instruction: &str = "";
let value: Option<&str>;
match curr_instr {
Some(instr) => {
let mut split_instr = instr.split_whitespace();
if let Some(val) = split_instr.next() {
instruction = val.trim();
}
value = split_instr.next();
},
_ => return Err(RuntimeError::NoInstructions)
}
match instruction {
"PUSH" => {
if let Some(value) = value {
if let Ok(parsed_value) = value.trim().parse::<i32>() {
self.stack.push(parsed_value);
self.add_to_history("PUSH".to_string(), Some(parsed_value));
self.remove_instruction();
return Ok(());
}
}
return Err(RuntimeError::InvalidCommand);
},
"POP" => {
if let Some(_) = value {
return Err(RuntimeError::InvalidCommand);
}
self.add_to_history("POP".to_string(), None);
self.stack.pop();
self.remove_instruction();
();
}
"ADD" => {
if let Some(_) = value {
return Err(RuntimeError::InvalidCommand);
}
let val1 = self.stack.pop();
let val2 = self.stack.pop();
match val1 {
Some(v1) => match val2 {
Some(v2) => {
self.add_to_history("ADD".to_string(), None);
self.stack.push(v1 + v2);
self.remove_instruction();
},
_ => {
self.stack.push(v1);
return Err(RuntimeError::StackUnderflow)
}
},
_ => return Err(RuntimeError::StackUnderflow)
}
},
"MUL" => {
if let Some(_) = value {
return Err(RuntimeError::InvalidCommand);
}
let val1 = self.stack.pop();
let val2 = self.stack.pop();
match val1 {
Some(v1) => match val2 {
Some(v2) => {
self.add_to_history("MUL".to_string(), None);
self.stack.push(v1 * v2);
self.remove_instruction();
},
_ => {
self.stack.push(v1);
return Err(RuntimeError::StackUnderflow)
}
},
_ => return Err(RuntimeError::StackUnderflow)
}
},
"SUB" => {
if let Some(_) = value {
return Err(RuntimeError::InvalidCommand);
}
let val1 = self.stack.pop();
let val2 = self.stack.pop();
match val1 {
Some(v1) => match val2 {
Some(v2) => {
self.add_to_history("SUB".to_string(), None);
self.stack.push(v1 - v2);
self.remove_instruction();
},
_ => {
self.stack.push(v1);
return Err(RuntimeError::StackUnderflow)
}
},
_ => return Err(RuntimeError::StackUnderflow)
}
},
"DIV" => {
if let Some(_) = value {
return Err(RuntimeError::InvalidCommand);
}
let val1 = self.stack.pop();
let val2 = self.stack.pop();
match val1 {
Some(v1) => match val2 {
Some(0) => {
self.stack.push(0);
self.stack.push(v1);
return Err(RuntimeError::DivideByZero);
},
Some(v2) => {
self.add_to_history("DIV".to_string(), None);
self.stack.push(v1 / v2);
self.remove_instruction();
},
_ => {
self.stack.push(v1);
return Err(RuntimeError::StackUnderflow)
}
},
_ => return Err(RuntimeError::StackUnderflow)
}
},
_ => return Err(RuntimeError::InvalidCommand)
}
return 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 last_instr = self.history_instructions.pop_back();
match last_instr {
Some(instr) => {
match instr.as_str() {
"ADD" | "SUB" | "MUL" | "DIV" => {
self.stack.pop();
let val1 = self.history_values.pop().unwrap();
let val2 = self.history_values.pop().unwrap();
self.stack.push(val2);
self.stack.push(val1);
self.instructions.push_front(instr);
},
"PUSH" => {
let val = self.stack.pop();
self.instructions.push_front(format!("{} {}", instr, val.unwrap().to_string()));
},
"POP" => {
self.stack.push(self.history_values.pop().unwrap());
self.instructions.push_front(instr);
},
_ => ()
}
},
None => return Err(RuntimeError::NoInstructions)
}
return Ok(());
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-1rr01q5/solution)
    Finished test [unoptimized + debuginfo] target(s) in 2.31s
     Running target/debug/deps/solution_test-8916805fc40a2dab

running 12 tests
test solution_test::test_arg_number ... FAILED
test solution_test::test_arithmetic_back ... FAILED
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 ... 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_arg_number stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Ok(())`,
 right: `Err(InvalidCommand)`: Should have been invalid: PUSH 1 2', tests/solution_test.rs:242:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- solution_test::test_arithmetic_back stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `[4, 5]`,
 right: `[-5, 5]`', tests/solution_test.rs:103:5

---- 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


failures:
    solution_test::test_arg_number
    solution_test::test_arithmetic_back
    solution_test::test_errors_1

test result: FAILED. 9 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out

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

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

Бетина качи първо решение на 18.01.2021 16:04 (преди над 4 години)