Решение на Reversible Interpreter от Симеон Николов

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

Към профила на Симеон Николов

Резултати

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

Код

use std::collections::VecDeque;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
#[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>,
back_instructions:Vec<String>,
back_stack:Vec<i32>
}
impl Interpreter {
pub fn new() -> Self {
Self
{
stack:Vec::<i32>::new(),
instructions:VecDeque::<String>::new(),
back_instructions:Vec::<String>::new(),
back_stack:Vec::<i32>::new()
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
let iterator= instructions.iter();
for i in iterator{
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> {
match self.current_instruction(){
None =>Err(RuntimeError::NoInstructions),
Some(mut_str) =>{
let mut iterator = mut_str.split_whitespace().peekable();
match iterator.next().unwrap(){
"PUSH" => match iterator.by_ref().count(){
1 => {
let new_value:i32 =mut_str.split_at(5).1.parse::<i32>().unwrap();//Чупи се на първия ънрап.Некст е празен
self.stack.push(new_value);
self.instructions.remove(0);
self.back_instructions.insert(self.back_instructions.len(),"PUSH".to_string());
Ok(())
},
_ =>Err(RuntimeError::InvalidCommand)
},
"POP" => match iterator.count(){
0 => {
self.back_stack.push(*self.stack.last().unwrap());
self.stack.pop();
self.instructions.remove(0);
self.back_instructions.insert(self.back_instructions.len(),"POP".to_string());
Ok(())
},
_ =>Err(RuntimeError::InvalidCommand)
},
"ADD" =>match iterator.count(){
0 => match self.stack.len(){
0 =>Err(RuntimeError::StackUnderflow),
1 =>Err(RuntimeError::StackUnderflow),
_ =>{
let first = self.stack.last().unwrap().clone();
self.back_stack.push(first);
self.stack.pop();
let second = self.stack.last().unwrap().clone();
self.back_stack.push(second);
self.stack.pop();
self.stack.push(first+second);
self.instructions.remove(0);
self.back_instructions.insert(self.back_instructions.len(),"ADD".to_string());
Ok(())
}
},
_ =>Err(RuntimeError::InvalidCommand)
},
"MUL" =>match iterator.count(){
0 => match self.stack.len(){
0 =>Err(RuntimeError::StackUnderflow),
1 =>Err(RuntimeError::StackUnderflow),
_ =>{
let first = self.stack.last().unwrap().clone();
self.back_stack.push(first);
self.stack.pop();
let second = self.stack.last().unwrap().clone();
self.back_stack.push(second);
self.stack.pop();
self.stack.push(first*second);
self.instructions.remove(0);
self.back_instructions.insert(self.back_instructions.len(),"MUL".to_string());
Ok(())
}
}
_ =>Err(RuntimeError::InvalidCommand)
},
"SUB" =>match iterator.count(){
0 => match self.stack.len(){
0 =>Err(RuntimeError::StackUnderflow),
1 =>Err(RuntimeError::StackUnderflow),
_ =>{
let first = self.stack.last().unwrap().clone();
self.back_stack.push(first);
self.stack.pop();
let second = self.stack.last().unwrap().clone();
self.back_stack.push(second);
self.stack.pop();
self.stack.push(first-second);
self.instructions.remove(0);
self.back_instructions.insert(self.back_instructions.len(),"SUB".to_string());
Ok(())
}
}
_=>Err(RuntimeError::InvalidCommand)
},
"DIV" =>match iterator.count(){
0 => match self.stack.len(){
0 =>Err(RuntimeError::StackUnderflow),
1 =>Err(RuntimeError::StackUnderflow),
_ =>{
let first = self.stack.last().unwrap().clone();
self.stack.pop();
match self.stack.last().unwrap(){
0 =>{
self.stack.push(first);
Err(RuntimeError::DivideByZero)
},
_=>{
self.back_stack.push(first);
let second = self.stack.last().unwrap().clone();
self.back_stack.push(second);
self.stack.pop();
self.stack.push(first/second);
self.instructions.remove(0);
self.back_instructions.insert(self.back_instructions.len(),"DIV".to_string());
Ok(())
}
}
}
}
_=>Err(RuntimeError::InvalidCommand)
},
_ =>Err(RuntimeError::InvalidCommand)
}
}
}
}
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.back_instructions.len(){
0 => Err(RuntimeError::NoInstructions),
_ => match self.back_instructions.last().unwrap().as_str(){
"PUSH" => {
let mut new_str = self.back_instructions.last().unwrap().clone();
self.back_instructions.pop();
let last = self.stack[self.stack.len()-1];
self.stack.pop();
new_str.push_str(" ");
new_str.push_str(last.to_string().as_str());
self.instructions.insert(0,new_str.to_string());
Ok(())
},
"POP" =>{
let last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
self.instructions.insert(0,"POP".to_string());
self.back_instructions.pop();
Ok(())
},
"ADD" =>{
self.stack.pop();
let mut last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
self.instructions.insert(0,"ADD".to_string());
self.back_instructions.pop();
Ok(())
},
"SUB" =>{
self.stack.pop();
let mut last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
self.instructions.insert(0,"SUB".to_string());
self.back_instructions.pop();
Ok(())
},
"MUL" =>{
self.stack.pop();
let mut last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
self.instructions.insert(0,"MUL".to_string());
self.back_instructions.pop();
Ok(())
},
"DIV"=>{
self.stack.pop();
let mut last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
last = self.back_stack.last().unwrap();
self.stack.push(*last);
self.back_stack.pop();
self.instructions.insert(0,"DIV".to_string());
self.back_instructions.pop();
Ok(())
}
_=> Err(RuntimeError::InvalidCommand)
}
}
}
}
//tests
#[test]
fn test_addition() {
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, &[]);
assert_eq!(interpreter.current_instruction().unwrap(),"PUSH 1");
let mut iterator = "PUSH 1".split_whitespace();
assert_eq!(iterator.next(),Some("PUSH"));
assert_eq!(iterator.next().unwrap().parse::<i32>().unwrap(),1);
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.add_instructions(&["ADD", "ADD"]);
assert_eq!(interpreter.run(), Err(RuntimeError::StackUnderflow));
}
#[test]
fn test_division_failure() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"DIV",
]);
assert_eq!(interpreter.instructions, &[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"DIV",
]);
interpreter.forward().unwrap();
interpreter.forward().unwrap();
interpreter.forward().unwrap();
assert_eq!(interpreter.instructions, &["DIV"]);
assert_eq!(interpreter.stack, &[1, 2, 3]);
interpreter.run().unwrap();
assert_eq!(interpreter.instructions.len(), 0);
assert_eq!(interpreter.stack, &[1, 1]);
interpreter.add_instructions(&["PUSH 0", "PUSH 1","DIV"]);
assert_eq!(interpreter.run(), Err(RuntimeError::DivideByZero));
assert_eq!(interpreter.stack, &[1, 1, 0, 1]);
}
#[test]
fn test_division_success() {
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&["PUSH 2", "PUSH 1","DIV"]);
interpreter.run().unwrap();
assert_eq!(interpreter.instructions.len(), 0);
assert_eq!(interpreter.stack,&[0]);
}
#[test]
fn test_back_function_div(){
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"DIV",
]);
assert_eq!(interpreter.back(),Err(RuntimeError::NoInstructions));
interpreter.run().unwrap();
interpreter.back().unwrap();
interpreter.back().unwrap();
interpreter.back().unwrap();
interpreter.back().unwrap();
assert_eq!(interpreter.instructions,&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"DIV",
]);
assert_eq!(interpreter.stack,&[]);
}
#[test]
fn test_back_function_pop(){
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"POP",
]);
interpreter.run().unwrap();
interpreter.back().unwrap();
assert_eq!(interpreter.instructions,&[
"POP",
]);
assert_eq!(interpreter.stack,&[1, 2, 3]);
}
#[test]
fn test_back_function_mul(){
let mut interpreter = Interpreter::new();
interpreter.add_instructions(&[
"PUSH 1",
"PUSH 2",
"PUSH 3",
"MUL",
]);
interpreter.run().unwrap();
assert_eq!(interpreter.stack,&[1, 6]);
interpreter.back().unwrap();
assert_eq!(interpreter.instructions,&[
"MUL",
]);
assert_eq!(interpreter.stack,&[1, 2, 3]);
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-gjhdu/solution)
    Finished test [unoptimized + debuginfo] target(s) in 2.39s
     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 ... 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_errors_1 stdout ----
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:77:73
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    solution_test::test_errors_1

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

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

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

Симеон качи първо решение на 18.01.2021 14:30 (преди над 4 години)