Решение на Reversible Interpreter от Ася Русанова
Резултати
- 13 точки от тестове
- 0 бонус точки
- 13 точки общо
- 10 успешни тест(а)
- 2 неуспешни тест(а)
Код
use std::str::FromStr;
#[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>,
pub operands: Vec<i32>,
pub operations: Vec<String>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions: VecDeque<String> = VecDeque::new();
let stack: Vec<i32> = Vec::new();
let operands: Vec<i32> = Vec::new();
let operations: Vec<String> = Vec::new();
return Self{instructions: instructions,stack: stack,operands: operands,operations: operations};
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instruction in instructions.iter() {
self.instructions.push_back(String::from(*instruction));
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
return self.instructions.front_mut();
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
match self.current_instruction() {
Some(instruction) => {
let mut remaining = instruction.split_off(3);
if instruction == "PUS" {
let number = remaining.split_off(2);
match i32::from_str(&number) {
Ok(n) => {
self.operations.push(String::from("PUSH"));
self.operands.push(n);
self.stack.push(n);
}
Err(_) => return Err(RuntimeError::InvalidCommand)
}
} else {
if !remaining.is_empty() {
return Err(RuntimeError::InvalidCommand);
} else {
if instruction == "POP" {
match self.stack.pop() {
Some(number) => {
self.operations.push(String::from("POP"));
self.operands.push(number);
},
None => return Err(RuntimeError::StackUnderflow)
}
} else {
let curr = instruction.clone();
match self.stack.pop() {
Some(upper_number) => {
match self.stack.pop() {
Some(lower_number) => {
let result: i32;
if curr == "DIV" {
if lower_number == 0 {
return Err(RuntimeError::DivideByZero);
} else {
self.operands.push(lower_number);
self.operands.push(upper_number);
self.operations.push(String::from("DIV"));
result = upper_number / lower_number;
}
} else {
self.operands.push(lower_number);
self.operands.push(upper_number);
if curr == "ADD" {
result = lower_number + upper_number;
} else if curr == "MUL" {
result = lower_number * upper_number;
} else if curr == "SUB" {
result = upper_number - lower_number;
} else {
return Err(RuntimeError::InvalidCommand);
}
self.operations.push(String::from(curr));
}
self.operands.push(result);
self.stack.push(result);
},
None => return Err(RuntimeError::StackUnderflow)
}
},
None => return Err(RuntimeError::StackUnderflow)
}
}
}
}
},
None => return Err(RuntimeError::NoInstructions)
}
self.instructions.pop_front();
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> {
match self.operations.pop() {
Some(command) => {
if command == "PUSH" {
self.stack.pop();
let mut instruction = String::from("PUSH ");
instruction.push_str(&self.operands.pop().unwrap().to_string());
self.instructions.push_front(instruction);
}
else if command == "POP" {
self.stack.push(self.operands.pop().unwrap());
self.instructions.push_front(String::from("POP"));
}
else {
self.operands.pop();
self.stack.pop();
let upper_number = self.operands.pop().unwrap();
let lower_number = self.operands.pop().unwrap();
self.stack.push(lower_number);
self.stack.push(upper_number);
self.instructions.push_front(command);
}
},
None => return Err(RuntimeError::NoInstructions)
}
return Ok(());
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-tzrw8v/solution) Finished test [unoptimized + debuginfo] target(s) in 2.44s Running target/debug/deps/solution_test-8916805fc40a2dab running 12 tests test solution_test::test_arg_number ... FAILED 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 ... FAILED 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: self.is_char_boundary(at)', /rustc/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/alloc/src/string.rs:1443:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ---- solution_test::test_invalid_args stdout ---- thread 'main' panicked at 'assertion failed: `(left == right)` left: `Err(StackUnderflow)`, right: `Err(InvalidCommand)`: Should have been invalid: VID', tests/solution_test.rs:265:9 failures: solution_test::test_arg_number solution_test::test_invalid_args test result: FAILED. 10 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out error: test failed, to rerun pass '--test solution_test'