Решение на Reversible Interpreter от Ивайло Кирязов

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

Към профила на Ивайло Кирязов

Резултати

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

Код

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
use std::collections::VecDeque;
#[derive(Debug, Default)]
pub struct PrevCommand {
pub command: String,
pub number: i32,
}
impl PrevCommand {
pub fn new(com: String, numb: i32) -> Self {
PrevCommand {
command: com,
number: numb,
}
}
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
pub back: Vec<PrevCommand>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::new(),
stack: Vec::new(),
back: Vec::new(),
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instr in instructions.iter() {
self.instructions.push_back(instr.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
let res = self.instructions.front_mut();
if res.is_none() {
return res;
}
Some(res.unwrap())
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
if self.instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let instr = self.instructions.front();
let comm;
if instr.as_ref().unwrap().contains("PUSH") {
let mut iter = instr.as_ref().unwrap().split_whitespace();
let mut res = iter.next();
res = iter.next();
if res.is_none() {
return Err(RuntimeError::InvalidCommand);
} else {
let number = res.unwrap().parse::<i32>();
if number.is_err() {
return Err(RuntimeError::InvalidCommand);
}
self.stack.push(res.unwrap().parse().unwrap());
comm = PrevCommand::new(instr.as_ref().unwrap().to_string(), 0);
}
} else if instr.as_ref().unwrap().contains("POP") {
let mut iter = instr.as_ref().unwrap().split_whitespace();
let mut res = iter.next();
res = iter.next();
if res.is_none() {
let numb = self.stack.pop();
if numb.is_none() {
return Err(RuntimeError::StackUnderflow);
}
comm = PrevCommand::new(instr.as_ref().unwrap().to_string(), numb.unwrap());
} else {
return Err(RuntimeError::InvalidCommand);
}
} else if instr.as_ref().unwrap().contains("ADD")
|| instr.as_ref().unwrap().contains("MUL")
|| instr.as_ref().unwrap().contains("SUB")
|| instr.as_ref().unwrap().contains("DIV")
{
let mut iter = instr.as_ref().unwrap().split_whitespace();
let mut res = iter.next();
res = iter.next();
if res.is_none() {
let first = self.stack.pop();
if first.is_none() {
return Err(RuntimeError::StackUnderflow);
}
let second = self.stack.pop();
if second.is_none() {
self.stack.push(first.unwrap());
return Err(RuntimeError::StackUnderflow);
}
let result;
if instr.as_ref().unwrap().contains("ADD") {
result = first.unwrap() + second.unwrap();
comm = PrevCommand::new(instr.as_ref().unwrap().to_string(), second.unwrap());
} else if instr.as_ref().unwrap().contains("MUL") {
result = first.unwrap() * second.unwrap();
comm = PrevCommand::new(instr.as_ref().unwrap().to_string(), second.unwrap());
} else if instr.as_ref().unwrap().contains("SUB") {
result = first.unwrap() - second.unwrap();
comm = PrevCommand::new(instr.as_ref().unwrap().to_string(), second.unwrap());
} else {
// DIV
if second.unwrap() == 0 {
self.stack.push(first.unwrap());
return Err(RuntimeError::DivideByZero);
}
result = first.unwrap() / second.unwrap();
comm = PrevCommand::new(instr.as_ref().unwrap().to_string(), second.unwrap());
}
self.stack.push(result);
} else {
return Err(RuntimeError::InvalidCommand);
}
} else {
return Err(RuntimeError::InvalidCommand);
}
let res = self.instructions.pop_front();
self.back.push(comm);
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> {
if self.back.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let instr = self.back.pop();
if instr.as_ref().unwrap().command.contains("PUSH") {
self.stack.pop();
} else if instr.as_ref().unwrap().command.contains("POP") {
self.stack.push(instr.as_ref().unwrap().number);
} else if instr.as_ref().unwrap().command.contains("ADD")
|| instr.as_ref().unwrap().command.contains("MUL")
|| instr.as_ref().unwrap().command.contains("SUB")
|| instr.as_ref().unwrap().command.contains("DIV")
{
if instr.as_ref().unwrap().command.contains("ADD") {
let first = self.stack.pop();
let res = first.unwrap() - instr.as_ref().unwrap().number;
self.stack.push(instr.as_ref().unwrap().number);
self.stack.push(res);
} else if instr.as_ref().unwrap().command.contains("MUL") {
let first = self.stack.pop();
let res = first.unwrap() / instr.as_ref().unwrap().number;
self.stack.push(instr.as_ref().unwrap().number);
self.stack.push(res);
} else if instr.as_ref().unwrap().command.contains("SUB") {
let first = self.stack.pop();
let res = first.unwrap() + instr.as_ref().unwrap().number;
self.stack.push(instr.as_ref().unwrap().number);
self.stack.push(res);
} else {
// DIV
let first = self.stack.pop();
let res = first.unwrap() * instr.as_ref().unwrap().number;
self.stack.push(instr.as_ref().unwrap().number);
self.stack.push(res);
}
}
self.instructions.push_front(instr.unwrap().command);
Ok(())
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-g8imlt/solution)
warning: value assigned to `res` is never read
  --> src/lib.rs:65:17
   |
65 |             let mut res = iter.next();
   |                 ^^^^^^^
   |
   = note: `#[warn(unused_assignments)]` on by default
   = help: maybe it is overwritten before being read?

warning: value assigned to `res` is never read
  --> src/lib.rs:80:17
   |
80 |             let mut res = iter.next();
   |                 ^^^^^^^
   |
   = help: maybe it is overwritten before being read?

warning: value assigned to `res` is never read
  --> src/lib.rs:98:17
   |
98 |             let mut res = iter.next();
   |                 ^^^^^^^
   |
   = help: maybe it is overwritten before being read?

warning: unused variable: `res`
   --> src/lib.rs:140:13
    |
140 |         let res = self.instructions.pop_front();
    |             ^^^ help: if this is intentional, prefix it with an underscore: `_res`
    |
    = note: `#[warn(unused_variables)]` on by default

warning: 4 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 ... 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 ... FAILED
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: `(left == right)`
  left: `Ok(())`,
 right: `Err(InvalidCommand)`: Should have been invalid: PUSH 1 2', tests/solution_test.rs:242:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- solution_test::test_div_2 stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `[5, 5]`,
 right: `[5, 7]`', tests/solution_test.rs:152:5

---- solution_test::test_invalid_args stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Err(StackUnderflow)`,
 right: `Err(InvalidCommand)`: Should have been invalid: ADDIFY', tests/solution_test.rs:265:9


failures:
    solution_test::test_arg_number
    solution_test::test_div_2
    solution_test::test_invalid_args

test result: FAILED. 9 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out

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

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

Ивайло качи първо решение на 18.01.2021 18:01 (преди над 4 години)