Решение на Reversible Interpreter от Даниел Стоянов

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

Към профила на Даниел Стоянов

Резултати

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

Код

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
fn string_to_number(str:&str) -> Result<i32, RuntimeError> {
match str.parse::<i32>() {
Ok(val) => Ok(val),
Err(_) => Err(RuntimeError::InvalidCommand),
}
}
fn update_history(interpeter: &mut Interpreter, temp: Interpreter) -> () {
interpeter.history.push((temp.instructions.clone(), temp.stack.clone()));
}
fn clear_last_history(interpeter: &mut Interpreter) -> () {
match interpeter.history.pop() {
_ => (),
}
}
fn update_current(interpeter: &mut Interpreter) -> Result<(),RuntimeError> {
let pair;
match interpeter.history.pop().clone() {
None => return Err(RuntimeError::NoInstructions),
Some(x) => pair = x,
}
interpeter.instructions = pair.0;
interpeter.stack = pair.1;
Ok(())
}
fn process_instruction(interpeter: &mut Interpreter, instruction: &String) -> Result<(), RuntimeError> {
let mut iter = instruction.trim().split_whitespace();
let command = iter.next().unwrap();
let arguments: Vec<i32> = {
let mut buffer: Vec<i32> = Vec::new();
if let Some(temp1) = iter.next() {
match string_to_number(temp1) {
Ok(val) => buffer.push(val),
Err(_) => return Err(RuntimeError::InvalidCommand),
}
}
if let Some(temp2) = iter.next() {
match string_to_number(temp2) {
Ok(val) => buffer.push(val),
Err(_) => return Err(RuntimeError::InvalidCommand),
}
}
buffer
};
match command {
"PUSH" | "Push" | "push" => {
match arguments.len() {
1 => interpeter.stack.push(arguments[0]),
_ => return Err(RuntimeError::InvalidCommand),
};
},
"POP" | "Pop" | "pop" => {
match arguments.len() {
0 => {
let mut temp;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val) => temp = val,
};
}
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"ADD" | "Add" | "add" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
let res = first + second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"MUL" | "Mul" | "mul" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
let res = first * second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"SUB" | "Sub" | "sub" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
let res = first - second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"DIV" | "Div" | "div" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
if second == 0 {
return Err(RuntimeError::DivideByZero);
}
let res = first / second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
_ => return Err(RuntimeError::InvalidCommand),
};
Ok(())
}
use std::collections::VecDeque;
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
history: Vec<(VecDeque<String>, Vec<i32>)>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {instructions: VecDeque::new(), stack: Vec::new(), history:Vec::new()}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instruction in instructions {
self.instructions.push_back(instruction.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
match self.instructions.front_mut() {
None => return None,
Some(instruction) => return Some(instruction),
}
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let temp = Interpreter {instructions: self.instructions.clone(), stack: self.stack.clone(), history:Vec::new()};
match self.current_instruction() {
None => return Err(RuntimeError::NoInstructions),
Some(instruction) => {
match self.instructions.pop_front() {
None => return Err(RuntimeError::NoInstructions),
Some(instruction) => {
match process_instruction(self, &instruction) {
Err(e) => {
self.add_instructions(&[instruction.as_str()]);
return Err(e);
},
Ok(()) => {
update_history(self, temp);
()
},
}
},
}
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> {
update_current(self)
}
}
// ------------------------------------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.instructions, &[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.stack, &[]);
interpreter.forward().unwrap();
interpreter.forward().unwrap();
interpreter.forward().unwrap();
assert_eq!(interpreter.instructions, &["ADD"]);
assert_eq!(interpreter.stack, &[1, 2, 3]);
interpreter.run().unwrap();
assert_eq!(interpreter.instructions.len(), 0);
assert_eq!(interpreter.stack, &[1, 5]);
interpreter.back().unwrap();
interpreter.back().unwrap();
assert_eq!(interpreter.instructions, &[
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.stack, &[1, 2]);
interpreter.add_instructions(&["ADD", "ADD"]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
assert_eq!(interpreter.current_instruction().unwrap(), "ADD");
}
#[test]
fn test_forward_push() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH ",
]);
assert_eq!(interpreter.forward(), Err(RuntimeError::InvalidCommand));
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 2 2",
]);
assert_eq!(interpreter.forward(), Err(RuntimeError::InvalidCommand));
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"Push 2",
"push 3",
"ADD",
]);
assert_eq!(interpreter.instructions, &["PUSH 1","Push 2", "push 3","ADD"]);
for i in 1..4 {
interpreter.forward();
}
assert_eq!(interpreter.stack, &[1,2,3]);
}
#[test]
fn test_forward_pop() {
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 3",
"POP 2",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::InvalidCommand));
}
#[test]
fn test_forward_add() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
println!("{:?}", interpreter);
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 3",
"Push 4",
"ADD",
]);
interpreter.run();
assert_eq!(interpreter.stack, [7]);
}
#[test]
fn test_forward_mul() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 3",
"MUL",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
println!("{:?}", interpreter);
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 3",
"Push 4",
"mul",
]);
interpreter.run();
assert_eq!(interpreter.stack, [12]);
}
#[test]
fn test_forward_div() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 3",
"div",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
println!("{:?}", interpreter);
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 4",
"Push 12",
"div",
]);
interpreter.run();
assert_eq!(interpreter.stack, [3]);
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-quuo97/solution)
warning: variable `temp` is assigned to, but never used
  --> src/lib.rs:64:25
   |
64 |                     let mut temp;
   |                         ^^^^^^^^
   |
   = note: `#[warn(unused_variables)]` on by default
   = note: consider using `_temp` instead

warning: value assigned to `temp` is never read
  --> src/lib.rs:67:38
   |
67 |                         Some(val) => temp = val,
   |                                      ^^^^
   |
   = note: `#[warn(unused_assignments)]` on by default
   = help: maybe it is overwritten before being read?

warning: unused variable: `instruction`
   --> src/lib.rs:201:18
    |
201 |             Some(instruction) => {
    |                  ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_instruction`

warning: variable does not need to be mutable
  --> src/lib.rs:64:25
   |
64 |                     let mut temp;
   |                         ----^^^^
   |                         |
   |                         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

warning: function is never used: `clear_last_history`
  --> src/lib.rs:19:4
   |
19 | fn clear_last_history(interpeter: &mut Interpreter) -> () {
   |    ^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default

warning: 5 warnings emitted

    Finished test [unoptimized + debuginfo] target(s) in 2.47s
     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 ... 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_instructions_after_error stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `["PUSH 3", "DIV"]`,
 right: `["DIV", "PUSH 3"]`', tests/solution_test.rs:215:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    solution_test::test_instructions_after_error

test result: FAILED. 11 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

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

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

Даниел качи първо решение на 20.01.2021 15:08 (преди 6 месеца)

Даниел качи решение на 20.01.2021 15:09 (преди 6 месеца)

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
fn string_to_number(str:&str) -> Result<i32, RuntimeError> {
match str.parse::<i32>() {
Ok(val) => Ok(val),
Err(_) => Err(RuntimeError::InvalidCommand),
}
}
fn update_history(interpeter: &mut Interpreter, temp: Interpreter) -> () {
interpeter.history.push((temp.instructions.clone(), temp.stack.clone()));
}
fn clear_last_history(interpeter: &mut Interpreter) -> () {
match interpeter.history.pop() {
_ => (),
}
}
fn update_current(interpeter: &mut Interpreter) -> Result<(),RuntimeError> {
let pair;
match interpeter.history.pop().clone() {
None => return Err(RuntimeError::NoInstructions),
Some(x) => pair = x,
}
interpeter.instructions = pair.0;
interpeter.stack = pair.1;
Ok(())
}
fn process_instruction(interpeter: &mut Interpreter, instruction: &String) -> Result<(), RuntimeError> {
let mut iter = instruction.trim().split_whitespace();
let command = iter.next().unwrap();
let arguments: Vec<i32> = {
let mut buffer: Vec<i32> = Vec::new();
if let Some(temp1) = iter.next() {
match string_to_number(temp1) {
Ok(val) => buffer.push(val),
Err(_) => return Err(RuntimeError::InvalidCommand),
}
}
if let Some(temp2) = iter.next() {
match string_to_number(temp2) {
Ok(val) => buffer.push(val),
Err(_) => return Err(RuntimeError::InvalidCommand),
}
}
buffer
};
match command {
"PUSH" | "Push" | "push" => {
match arguments.len() {
1 => interpeter.stack.push(arguments[0]),
_ => return Err(RuntimeError::InvalidCommand),
};
},
"POP" | "Pop" | "pop" => {
match arguments.len() {
0 => {
let mut temp;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val) => temp = val,
};
}
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"ADD" | "Add" | "add" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
let res = first + second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"MUL" | "Mul" | "mul" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
let res = first * second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"SUB" | "Sub" | "sub" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
let res = first - second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
"DIV" | "Div" | "div" => {
match arguments.len() {
0 => {
let first;
let second;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val1) => {
first = val1;
match interpeter.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(val2) => second = val2,
};
},
};
if second == 0 {
return Err(RuntimeError::DivideByZero);
}
let res = first / second;
interpeter.stack.push(res);
},
_ => return Err(RuntimeError::InvalidCommand),
};
()
},
_ => return Err(RuntimeError::InvalidCommand),
};
Ok(())
}
use std::collections::VecDeque;
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
history: Vec<(VecDeque<String>, Vec<i32>)>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {instructions: VecDeque::new(), stack: Vec::new(), history:Vec::new()}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instruction in instructions {
self.instructions.push_back(instruction.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
match self.instructions.front_mut() {
None => return None,
Some(instruction) => return Some(instruction),
}
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let temp = Interpreter {instructions: self.instructions.clone(), stack: self.stack.clone(), history:Vec::new()};
match self.current_instruction() {
None => return Err(RuntimeError::NoInstructions),
Some(instruction) => {
match self.instructions.pop_front() {
None => return Err(RuntimeError::NoInstructions),
Some(instruction) => {
match process_instruction(self, &instruction) {
Err(e) => {
self.add_instructions(&[instruction.as_str()]);
return Err(e);
},
Ok(()) => {
update_history(self, temp);
()
},
}
},
}
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> {
update_current(self)
}
}
// ------------------------------------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.instructions, &[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.stack, &[]);
interpreter.forward().unwrap();
interpreter.forward().unwrap();
interpreter.forward().unwrap();
assert_eq!(interpreter.instructions, &["ADD"]);
assert_eq!(interpreter.stack, &[1, 2, 3]);
interpreter.run().unwrap();
assert_eq!(interpreter.instructions.len(), 0);
assert_eq!(interpreter.stack, &[1, 5]);
interpreter.back().unwrap();
interpreter.back().unwrap();
assert_eq!(interpreter.instructions, &[
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.stack, &[1, 2]);
interpreter.add_instructions(&["ADD", "ADD"]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
assert_eq!(interpreter.current_instruction().unwrap(), "ADD");
}
#[test]
fn test_forward_push() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH ",
]);
assert_eq!(interpreter.forward(), Err(RuntimeError::InvalidCommand));
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 2 2",
]);
assert_eq!(interpreter.forward(), Err(RuntimeError::InvalidCommand));
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"Push 2",
"push 3",
"ADD",
]);
assert_eq!(interpreter.instructions, &["PUSH 1","Push 2", "push 3","ADD"]);
for i in 1..4 {
interpreter.forward();
}
assert_eq!(interpreter.stack, &[1,2,3]);
}
#[test]
fn test_forward_pop() {
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 3",
"POP 2",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::InvalidCommand));
}
#[test]
fn test_forward_add() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 3",
"ADD",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
println!("{:?}", interpreter);
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 3",
"Push 4",
"ADD",
]);
interpreter.run();
assert_eq!(interpreter.stack, [7]);
}
#[test]
fn test_forward_mul() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 3",
- "ADD",
+ "MUL",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
println!("{:?}", interpreter);
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 3",
"Push 4",
"mul",
]);
interpreter.run();
assert_eq!(interpreter.stack, [12]);
}
#[test]
fn test_forward_div() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 3",
- "ADD",
+ "div",
]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
println!("{:?}", interpreter);
let mut interpreter = Interpreter::new();
assert_eq!(interpreter.forward(), Err(RuntimeError::NoInstructions));
interpreter.add_instructions(&[
"PUSH 4",
"Push 12",
"div",
]);
interpreter.run();
assert_eq!(interpreter.stack, [3]);
}
}
+