Решение на Reversible Interpreter от Антонина Ускова

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

Към профила на Антонина Ускова

Резултати

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

Код

use std::{collections::VecDeque, fmt, num::ParseIntError, str::FromStr};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
impl From<ParseIntError> for RuntimeError {
fn from(_err: ParseIntError) -> RuntimeError {
RuntimeError::InvalidCommand
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
Push(i32),
Pop,
Add,
Mul,
Sub,
Div,
}
impl fmt::Display for Command {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Command::Push(num) => write!(f, "PUSH {}", num),
Command::Pop => write!(f, "POP"),
Command::Add => write!(f, "ADD"),
Command::Mul => write!(f, "MUL"),
Command::Sub => write!(f, "SUB"),
Command::Div => write!(f, "DIV"),
}
}
}
impl FromStr for Command {
type Err = RuntimeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim().to_lowercase();
let mut tokens = s.split_whitespace();
let err = Err(RuntimeError::InvalidCommand);
let command = match tokens.next() {
Some("push") => match tokens.next() {
Some(num_str) => {
let num = num_str.parse::<i32>()?;
Ok(Command::Push(num))
}
None => err,
},
Some("pop") => Ok(Command::Pop),
Some("add") => Ok(Command::Add),
Some("mul") => Ok(Command::Mul),
Some("sub") => Ok(Command::Sub),
Some("div") => Ok(Command::Div),
Some(_) => err,
None => err,
};
match tokens.next() {
Some(_) => Err(RuntimeError::InvalidCommand),
None => command,
}
}
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
reverse_instructions: Vec<Command>,
reverse_stack: Vec<i32>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions: VecDeque<String> = VecDeque::new();
let stack: Vec<i32> = Vec::new();
let reverse_instructions: Vec<Command> = Vec::new();
let reverse_stack: Vec<i32> = Vec::new();
Self {
instructions,
stack,
reverse_instructions,
reverse_stack,
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for inst in instructions.iter() {
self.instructions.push_back(String::from(*inst));
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let command = match self.instructions.front() {
Some(command) => command.parse::<Command>(),
None => Err(RuntimeError::NoInstructions),
};
let command = command?;
let result = self.exec_command(&command);
if result.is_ok() {
self.instructions
.pop_front()
.ok_or(RuntimeError::InvalidCommand)?;
self.reverse_instructions.push(command);
};
result
}
fn exec_command(&mut self, command: &Command) -> Result<(), RuntimeError> {
let err = RuntimeError::StackUnderflow;
match command {
Command::Push(num) => {
self.stack.push(*num);
}
Command::Pop => {
let num = self.stack.pop().ok_or(err.clone())?;
self.reverse_stack.push(num);
}
_ => {
let first = self.stack.pop().ok_or(err.clone())?;
let second = match self.stack.pop() {
Some(second) => second,
None => {
self.stack.push(first);
return Err(err.clone());
}
};
match command {
Command::Add => {
self.stack.push(first + second);
}
Command::Mul => {
self.stack.push(first * second);
}
Command::Sub => {
self.stack.push(first - second);
}
Command::Div => {
if second == 0 {
self.stack.push(second);
self.stack.push(first);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(first / second);
}
_ => unreachable!(),
};
self.reverse_stack.push(first);
self.reverse_stack.push(second);
}
};
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 command = self
.reverse_instructions
.pop()
.ok_or(RuntimeError::NoInstructions)?;
match command {
Command::Push(_) => self.exec_command(&Command::Pop),
Command::Pop => {
let num = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
self.exec_command(&Command::Push(num))
}
_ => {
self.stack.pop().ok_or(RuntimeError::InvalidCommand)?;
let first = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
let second = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
self.exec_command(&Command::Push(first))?;
self.exec_command(&Command::Push(second))?;
Ok(())
}
}?;
self.instructions.push_front(command.to_string());
Ok(())
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-9qi4dq/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 ... 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 ... 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

failures:

---- solution_test::test_arithmetic_back stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `[5, 9]`,
 right: `[9, 4]`', tests/solution_test.rs:108:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    solution_test::test_arithmetic_back

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

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

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

Антонина качи първо решение на 20.01.2021 13:45 (преди 6 месеца)

Антонина качи решение на 20.01.2021 14:01 (преди 6 месеца)

use std::{collections::VecDeque, fmt, num::ParseIntError, str::FromStr};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
impl From<ParseIntError> for RuntimeError {
fn from(_err: ParseIntError) -> RuntimeError {
RuntimeError::InvalidCommand
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
Push(i32),
Pop,
Add,
Mul,
Sub,
Div,
}
impl fmt::Display for Command {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Command::Push(num) => write!(f, "PUSH {}", num),
Command::Pop => write!(f, "POP"),
Command::Add => write!(f, "ADD"),
Command::Mul => write!(f, "MUL"),
Command::Sub => write!(f, "SUB"),
Command::Div => write!(f, "DIV"),
}
}
}
impl FromStr for Command {
type Err = RuntimeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim().to_lowercase();
let mut tokens = s.split_whitespace();
let err = Err(RuntimeError::InvalidCommand);
let command = match tokens.next() {
Some("push") => match tokens.next() {
Some(num_str) => {
let num = num_str.parse::<i32>()?;
Ok(Command::Push(num))
}
None => err,
},
Some("pop") => Ok(Command::Pop),
Some("add") => Ok(Command::Add),
Some("mul") => Ok(Command::Mul),
Some("sub") => Ok(Command::Sub),
Some("div") => Ok(Command::Div),
Some(_) => err,
None => err,
};
match tokens.next() {
Some(_) => Err(RuntimeError::InvalidCommand),
None => command,
}
}
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
reverse_instructions: Vec<Command>,
reverse_stack: Vec<i32>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions: VecDeque<String> = VecDeque::new();
let stack: Vec<i32> = Vec::new();
let reverse_instructions: Vec<Command> = Vec::new();
let reverse_stack: Vec<i32> = Vec::new();
Self {
instructions,
stack,
reverse_instructions,
reverse_stack,
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for inst in instructions.iter() {
self.instructions.push_back(String::from(*inst));
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let command = match self.instructions.front() {
Some(command) => command.parse::<Command>(),
None => Err(RuntimeError::NoInstructions),
};
let command = command?;
let result = self.exec_command(&command);
if result.is_ok() {
self.instructions
.pop_front()
.ok_or(RuntimeError::InvalidCommand)?;
self.reverse_instructions.push(command);
};
result
}
fn exec_command(&mut self, command: &Command) -> Result<(), RuntimeError> {
let err = RuntimeError::StackUnderflow;
match command {
Command::Push(num) => {
self.stack.push(*num);
}
Command::Pop => {
let num = self.stack.pop().ok_or(err.clone())?;
self.reverse_stack.push(num);
}
_ => {
let first = self.stack.pop().ok_or(err.clone())?;
let second = self.stack.pop().ok_or(err.clone())?;
match command {
Command::Add => {
self.stack.push(first + second);
}
Command::Mul => {
self.stack.push(first * second);
}
Command::Sub => {
self.stack.push(first - second);
}
Command::Div => {
if second == 0 {
+ self.stack.push(second);
+ self.stack.push(first);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(first / second);
}
_ => unreachable!(),
};
self.reverse_stack.push(first);
self.reverse_stack.push(second);
}
};
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 command = self
.reverse_instructions
.pop()
.ok_or(RuntimeError::NoInstructions)?;
match command {
- Command::Push(_) => self.exec_command(&Command::Pop),
+ Command::Push(_) => {
+ self.exec_command(&Command::Pop)}
+ ,
Command::Pop => {
let num = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
self.exec_command(&Command::Push(num))
}
_ => {
self.stack.pop().ok_or(RuntimeError::InvalidCommand)?;
let first = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
let second = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
self.exec_command(&Command::Push(first))?;
self.exec_command(&Command::Push(second))?;
Ok(())
}
}?;
self.instructions.push_front(command.to_string());
Ok(())
}
-}
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_add_instr() {
+ let mut interpreter = Interpreter::new();
+ interpreter.add_instructions(&["PUSH 1", "PUSH 2"]);
+ let mut res: VecDeque<String> = VecDeque::new();
+ res.push_back(String::from("PUSH 1"));
+ res.push_back(String::from("PUSH 2"));
+
+ assert_eq!(interpreter.instructions, res)
+ }
+
+ #[test]
+ fn test_parse_command() {
+ assert_eq!(Command::Push(-1), "PUSH -1".parse::<Command>().unwrap());
+ assert_eq!(Command::Pop, "POP".parse::<Command>().unwrap());
+ assert_eq!(Command::Add, "ADD".parse::<Command>().unwrap());
+ assert_eq!(Command::Mul, "MUL".parse::<Command>().unwrap());
+ assert_eq!(Command::Sub, "SUB".parse::<Command>().unwrap());
+ assert_eq!(Command::Div, "DIV".parse::<Command>().unwrap())
+ }
+}

Антонина качи решение на 20.01.2021 14:10 (преди 6 месеца)

use std::{collections::VecDeque, fmt, num::ParseIntError, str::FromStr};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
impl From<ParseIntError> for RuntimeError {
fn from(_err: ParseIntError) -> RuntimeError {
RuntimeError::InvalidCommand
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
Push(i32),
Pop,
Add,
Mul,
Sub,
Div,
}
impl fmt::Display for Command {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Command::Push(num) => write!(f, "PUSH {}", num),
Command::Pop => write!(f, "POP"),
Command::Add => write!(f, "ADD"),
Command::Mul => write!(f, "MUL"),
Command::Sub => write!(f, "SUB"),
Command::Div => write!(f, "DIV"),
}
}
}
impl FromStr for Command {
type Err = RuntimeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim().to_lowercase();
let mut tokens = s.split_whitespace();
let err = Err(RuntimeError::InvalidCommand);
let command = match tokens.next() {
Some("push") => match tokens.next() {
Some(num_str) => {
let num = num_str.parse::<i32>()?;
Ok(Command::Push(num))
}
None => err,
},
Some("pop") => Ok(Command::Pop),
Some("add") => Ok(Command::Add),
Some("mul") => Ok(Command::Mul),
Some("sub") => Ok(Command::Sub),
Some("div") => Ok(Command::Div),
Some(_) => err,
None => err,
};
match tokens.next() {
Some(_) => Err(RuntimeError::InvalidCommand),
None => command,
}
}
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
reverse_instructions: Vec<Command>,
reverse_stack: Vec<i32>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions: VecDeque<String> = VecDeque::new();
let stack: Vec<i32> = Vec::new();
let reverse_instructions: Vec<Command> = Vec::new();
let reverse_stack: Vec<i32> = Vec::new();
Self {
instructions,
stack,
reverse_instructions,
reverse_stack,
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for inst in instructions.iter() {
self.instructions.push_back(String::from(*inst));
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let command = match self.instructions.front() {
Some(command) => command.parse::<Command>(),
None => Err(RuntimeError::NoInstructions),
};
let command = command?;
let result = self.exec_command(&command);
if result.is_ok() {
self.instructions
.pop_front()
.ok_or(RuntimeError::InvalidCommand)?;
self.reverse_instructions.push(command);
};
result
}
fn exec_command(&mut self, command: &Command) -> Result<(), RuntimeError> {
let err = RuntimeError::StackUnderflow;
match command {
Command::Push(num) => {
self.stack.push(*num);
}
Command::Pop => {
let num = self.stack.pop().ok_or(err.clone())?;
self.reverse_stack.push(num);
}
_ => {
let first = self.stack.pop().ok_or(err.clone())?;
- let second = self.stack.pop().ok_or(err.clone())?;
+ let second = match self.stack.pop() {
+ Some(second) => second,
+ None => {
+ self.stack.push(first);
+ return Err(err.clone());
+ }
+ };
+
match command {
Command::Add => {
self.stack.push(first + second);
}
Command::Mul => {
self.stack.push(first * second);
}
Command::Sub => {
self.stack.push(first - second);
}
Command::Div => {
if second == 0 {
self.stack.push(second);
self.stack.push(first);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(first / second);
}
_ => unreachable!(),
};
self.reverse_stack.push(first);
self.reverse_stack.push(second);
}
};
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 command = self
.reverse_instructions
.pop()
.ok_or(RuntimeError::NoInstructions)?;
match command {
- Command::Push(_) => {
- self.exec_command(&Command::Pop)}
- ,
+ Command::Push(_) => self.exec_command(&Command::Pop),
Command::Pop => {
let num = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
self.exec_command(&Command::Push(num))
}
_ => {
self.stack.pop().ok_or(RuntimeError::InvalidCommand)?;
let first = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
let second = self
.reverse_stack
.pop()
.ok_or(RuntimeError::InvalidCommand)?;
self.exec_command(&Command::Push(first))?;
self.exec_command(&Command::Push(second))?;
Ok(())
}
}?;
self.instructions.push_front(command.to_string());
Ok(())
}
-}
-
+}
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_add_instr() {
- let mut interpreter = Interpreter::new();
- interpreter.add_instructions(&["PUSH 1", "PUSH 2"]);
- let mut res: VecDeque<String> = VecDeque::new();
- res.push_back(String::from("PUSH 1"));
- res.push_back(String::from("PUSH 2"));
-
- assert_eq!(interpreter.instructions, res)
- }
-
- #[test]
- fn test_parse_command() {
- assert_eq!(Command::Push(-1), "PUSH -1".parse::<Command>().unwrap());
- assert_eq!(Command::Pop, "POP".parse::<Command>().unwrap());
- assert_eq!(Command::Add, "ADD".parse::<Command>().unwrap());
- assert_eq!(Command::Mul, "MUL".parse::<Command>().unwrap());
- assert_eq!(Command::Sub, "SUB".parse::<Command>().unwrap());
- assert_eq!(Command::Div, "DIV".parse::<Command>().unwrap())
- }
-}