Решение на Reversible Interpreter от Кирил Костов

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

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

Резултати

  • 15 точки от тестове
  • 0 бонус точки
  • 15 точки общо
  • 12 успешни тест(а)
  • 0 неуспешни тест(а)

Код

use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum Instruction {
Push,
Pop,
Add,
Mul,
Sub,
Div,
}
#[derive(Clone, Debug)]
struct ReverseInstruction {
pub instruction: Instruction,
pub val1: i32,
pub val2: i32,
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
test_rev: Vec<ReverseInstruction>,
}
impl Interpreter {
pub fn new() -> Self {
Interpreter {
instructions: VecDeque::<String>::new(),
stack: Vec::<i32>::new(),
test_rev: Vec::<ReverseInstruction>::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> {
self.instructions.front_mut()
}
fn expect_none<'a, I>(iter: &mut I) -> Result<(), RuntimeError>
where
I: Iterator<Item = &'a str>,
{
match iter.next() {
Some(_) => return Err(RuntimeError::InvalidCommand),
None => Ok(()),
}
}
fn push<'a, I>(&mut self, values: &mut I) -> Result<(), RuntimeError>
where
I: Iterator<Item = &'a str>,
{
let val = match values.next() {
Some(val) => val,
None => return Err(RuntimeError::InvalidCommand),
};
Self::expect_none(values)?;
let val = match val.parse::<i32>() {
Ok(int) => int,
Err(_) => return Err(RuntimeError::InvalidCommand),
};
self.stack.push(val);
Ok(())
}
fn pop(&mut self) -> Result<i32, RuntimeError> {
match self.stack.pop() {
Some(val) => return Ok(val),
None => return Err(RuntimeError::StackUnderflow),
}
}
fn add(&mut self) -> Result<(i32, i32), RuntimeError> {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let a = self.pop()?;
let b = self.pop()?;
self.stack.push(a + b);
Ok((a, b))
}
fn multiply(&mut self) -> Result<(i32, i32), RuntimeError> {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let a = self.pop()?;
let b = self.pop()?;
self.stack.push(a * b);
Ok((a, b))
}
fn subtract(&mut self) -> Result<(i32, i32), RuntimeError> {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let a = self.pop()?;
let b = self.pop()?;
self.stack.push(a - b);
Ok((a, b))
}
fn divide(&mut self) -> Result<(i32, i32), RuntimeError> {
if self.stack.len() < 2 {
return Err(RuntimeError::StackUnderflow);
}
let a = self.pop()?;
let b = self.pop()?;
if b == 0 {
self.stack.push(b);
self.stack.push(a);
return Err(RuntimeError::DivideByZero);
}
self.stack.push(a / b);
Ok((a, b))
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let instruction = match self.instructions.front() {
Some(value) => value.clone(),
None => return Err(RuntimeError::NoInstructions),
};
let mut iter = instruction.split_whitespace();
match iter.next() {
Some("PUSH") => {
self.push(&mut iter)?;
self.test_rev.push(ReverseInstruction {
instruction: Instruction::Pop,
val1: 0,
val2: 0,
});
}
Some("POP") => {
Self::expect_none(&mut iter)?;
let val = self.pop()?;
self.test_rev.push(ReverseInstruction {
instruction: Instruction::Push,
val1: val,
val2: 0,
});
}
Some("ADD") => {
Self::expect_none(&mut iter)?;
let (val1, val2) = self.add()?;
self.test_rev.push(ReverseInstruction {
instruction: Instruction::Add,
val1: val1,
val2: val2,
});
}
Some("MUL") => {
Self::expect_none(&mut iter)?;
let (val1, val2) = self.multiply()?;
self.test_rev.push(ReverseInstruction {
instruction: Instruction::Mul,
val1: val1,
val2: val2,
});
}
Some("SUB") => {
Self::expect_none(&mut iter)?;
let (val1, val2) = self.subtract()?;
self.test_rev.push(ReverseInstruction {
instruction: Instruction::Sub,
val1: val1,
val2: val2,
});
}
Some("DIV") => {
Self::expect_none(&mut iter)?;
let (val1, val2) = self.divide()?;
self.test_rev.push(ReverseInstruction {
instruction: Instruction::Div,
val1: val1,
val2: val2,
});
}
Some(_) => return Err(RuntimeError::InvalidCommand),
None => return Err(RuntimeError::NoInstructions),
}
self.instructions.pop_front();
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 rev_instr = match self.test_rev.pop() {
Some(value) => value.clone(),
None => return Err(RuntimeError::NoInstructions),
};
match rev_instr.instruction {
Instruction::Pop => {
let val = self.pop()?;
self.instructions.push_front(format!("PUSH {}", val));
}
Instruction::Push => {
self.stack.push(rev_instr.val1);
self.instructions.push_front(String::from("POP"))
}
Instruction::Add => {
self.pop()?;
self.stack.push(rev_instr.val2);
self.stack.push(rev_instr.val1);
self.instructions.push_front(String::from("ADD"));
}
Instruction::Mul => {
self.pop()?;
self.stack.push(rev_instr.val2);
self.stack.push(rev_instr.val1);
self.instructions.push_front(String::from("MUL"));
}
Instruction::Sub => {
self.pop()?;
self.stack.push(rev_instr.val2);
self.stack.push(rev_instr.val1);
self.instructions.push_front(String::from("SUB"));
}
Instruction::Div => {
self.pop()?;
self.stack.push(rev_instr.val2);
self.stack.push(rev_instr.val1);
self.instructions.push_front(String::from("DIV"));
}
}
Ok(())
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-ox79pz/solution)
    Finished test [unoptimized + debuginfo] target(s) in 2.46s
     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

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

Кирил качи първо решение на 19.01.2021 10:57 (преди над 4 години)