Решение на Reversible Interpreter от Йоана Зелова
Резултати
- 15 точки от тестове
- 0 бонус точки
- 15 точки общо
- 12 успешни тест(а)
- 0 неуспешни тест(а)
Код
#[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>,
rowback_instructions: VecDeque<String>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions = VecDeque::new();
let stack = Vec::new();
let rowback_instructions = VecDeque::new();
Interpreter {
instructions,
stack,
rowback_instructions,
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instr in instructions {
self.instructions.push_back(String::from(*instr));
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
if self.instructions.len() == 0 {
return None;
} else {
return Some(&mut self.instructions[0]);
}
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
if self.instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let string = self.instructions[0].clone();
let words: Vec<&str> = string.split_whitespace().collect();
if words.len() == 0 {
return Err(RuntimeError::NoInstructions);
} else {
match words[0] {
"PUSH" => {
if words.len() != 2 {
return Err(RuntimeError::InvalidCommand);
} else {
let number = words[1].parse::<i32>();
match number {
Err(_) => Err(RuntimeError::InvalidCommand),
Ok(num) => {
self.stack.push(num);
self.instructions.pop_front();
self.rowback_instructions.push_front(String::from("POP"));
return Ok(());
}
}
}
}
"POP" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
if self.stack.len() == 0 {
return Err(RuntimeError::StackUnderflow);
} else {
let val = self.stack.pop();
match val {
None => return Err(RuntimeError::StackUnderflow),
Some(value) => {
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("PUSH {}", value)));
return Ok(());
}
}
}
}
}
"ADD" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow);
}
Some(y) => {
self.stack.push(x + y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("SUB {} {}", y, x,)));
return Ok(());
}
},
}
}
}
"MUL" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow);
}
Some(y) => {
self.stack.push(x * y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("DIV {} {}", y, x,)));
return Ok(());
}
},
}
}
}
"SUB" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow);
}
Some(y) => {
self.stack.push(x - y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("ADD {} {}", y, x)));
return Ok(());
}
},
}
}
}
"DIV" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow);
}
Some(y) => {
if y == 0 {
self.stack.push(y);
self.stack.push(x);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(x / y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("MUL {} {}", y, x)));
return Ok(());
}
},
}
}
}
&_ => {
return 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> {
if self.rowback_instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let string = self.rowback_instructions[0].clone();
let words: Vec<&str> = string.split_whitespace().collect();
if words.len() == 0 {
return Err(RuntimeError::NoInstructions);
} else {
match words[0] {
"PUSH" => {
if words.len() != 2 {
return Err(RuntimeError::InvalidCommand);
} else {
let number = words[1].parse::<i32>();
match number {
Err(_) => Err(RuntimeError::InvalidCommand),
Ok(num) => {
self.stack.push(num);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from("POP"));
return Ok(());
}
}
}
}
"POP" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
if self.stack.len() == 0 {
return Err(RuntimeError::StackUnderflow);
} else {
let val = self.stack.pop();
match val {
None => return Err(RuntimeError::StackUnderflow),
Some(value) => {
self.rowback_instructions.pop_front();
self.instructions
.push_front(String::from(format!("PUSH {}", value)));
return Ok(());
}
}
}
}
}
"ADD" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("SUB")));
return Ok(());
}
},
},
}
}
}
"MUL" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("DIV")));
return Ok(());
}
},
},
}
}
}
"SUB" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("ADD",)));
return Ok(());
}
},
},
}
}
}
"DIV" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("MUL")));
return Ok(());
}
},
},
}
}
}
&_ => {
return Err(RuntimeError::InvalidCommand);
}
}
}
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-10olx7/solution) Finished test [unoptimized + debuginfo] target(s) in 2.29s 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 ... 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 test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
История (2 версии и 0 коментара)
Йоана качи решение на 19.01.2021 08:39 (преди над 4 години)
#[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>,
rowback_instructions: VecDeque<String>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions = VecDeque::new();
let stack = Vec::new();
let rowback_instructions = VecDeque::new();
Interpreter {
instructions,
stack,
rowback_instructions,
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instr in instructions {
self.instructions.push_back(String::from(*instr));
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
if self.instructions.len() == 0 {
return None;
} else {
return Some(&mut self.instructions[0]);
}
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
if self.instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let string = self.instructions[0].clone();
let words: Vec<&str> = string.split_whitespace().collect();
if words.len() == 0 {
return Err(RuntimeError::NoInstructions);
} else {
match words[0] {
"PUSH" => {
if words.len() != 2 {
return Err(RuntimeError::InvalidCommand);
} else {
let number = words[1].parse::<i32>();
match number {
Err(_) => Err(RuntimeError::InvalidCommand),
Ok(num) => {
self.stack.push(num);
self.instructions.pop_front();
self.rowback_instructions.push_front(String::from("POP"));
return Ok(());
}
}
}
}
"POP" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
if self.stack.len() == 0 {
return Err(RuntimeError::StackUnderflow);
} else {
let val = self.stack.pop();
match val {
None => return Err(RuntimeError::StackUnderflow),
Some(value) => {
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("PUSH {}", value)));
return Ok(());
}
}
}
}
}
"ADD" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
- None => return Err(RuntimeError::StackUnderflow),
+ None => {
+ self.stack.push(x);
+ return Err(RuntimeError::StackUnderflow);
+ }
Some(y) => {
self.stack.push(x + y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("SUB {} {}", y, x,)));
return Ok(());
}
},
}
}
}
"MUL" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
- None => return Err(RuntimeError::StackUnderflow),
+ None => {
+ self.stack.push(x);
+ return Err(RuntimeError::StackUnderflow);
+ }
Some(y) => {
self.stack.push(x * y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("DIV {} {}", y, x,)));
return Ok(());
}
},
}
}
}
"SUB" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
- None => return Err(RuntimeError::StackUnderflow),
+ None => {
+ self.stack.push(x);
+ return Err(RuntimeError::StackUnderflow);
+ }
Some(y) => {
self.stack.push(x - y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("ADD {} {}", y, x)));
return Ok(());
}
},
}
}
}
"DIV" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(x) => match self.stack.pop() {
- None => return Err(RuntimeError::StackUnderflow),
+ None => {
+ self.stack.push(x);
+ return Err(RuntimeError::StackUnderflow);
+ }
Some(y) => {
if y == 0 {
+ self.stack.push(y);
+ self.stack.push(x);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(x / y);
self.instructions.pop_front();
self.rowback_instructions
.push_front(String::from(format!("MUL {} {}", y, x)));
return Ok(());
}
},
}
}
}
&_ => {
return 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> {
if self.rowback_instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let string = self.rowback_instructions[0].clone();
let words: Vec<&str> = string.split_whitespace().collect();
if words.len() == 0 {
return Err(RuntimeError::NoInstructions);
} else {
match words[0] {
"PUSH" => {
if words.len() != 2 {
return Err(RuntimeError::InvalidCommand);
} else {
let number = words[1].parse::<i32>();
match number {
Err(_) => Err(RuntimeError::InvalidCommand),
Ok(num) => {
self.stack.push(num);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from("POP"));
return Ok(());
}
}
}
}
"POP" => {
if words.len() != 1 {
return Err(RuntimeError::InvalidCommand);
} else {
if self.stack.len() == 0 {
return Err(RuntimeError::StackUnderflow);
} else {
let val = self.stack.pop();
match val {
None => return Err(RuntimeError::StackUnderflow),
Some(value) => {
self.rowback_instructions.pop_front();
self.instructions
.push_front(String::from(format!("PUSH {}", value)));
return Ok(());
}
}
}
}
}
"ADD" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("SUB")));
return Ok(());
}
},
},
}
}
}
"MUL" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("DIV")));
return Ok(());
}
},
},
}
}
}
"SUB" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("ADD",)));
return Ok(());
}
},
},
}
}
}
"DIV" => {
if words.len() != 3 {
return Err(RuntimeError::InvalidCommand);
} else {
match self.stack.pop() {
None => return Err(RuntimeError::StackUnderflow),
Some(_) => match words[1].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(y) => match words[2].parse::<i32>() {
Err(_) => return Err(RuntimeError::StackUnderflow),
Ok(z) => {
self.stack.push(y);
self.stack.push(z);
self.rowback_instructions.pop_front();
self.instructions.push_front(String::from(format!("MUL")));
return Ok(());
}
},
},
}
}
}
&_ => {
return Err(RuntimeError::InvalidCommand);
}
}
}
}
}