Решение на Reversible Interpreter от Ивайло Атовски

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

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

Резултати

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

Код

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
use std::{collections::VecDeque, process::Command, vec};
#[derive(Debug)]
enum History {
Push(),
Pop(i32),
Add((i32, i32)),
Mul((i32, i32)),
Sub((i32, i32)),
Div((i32, i32)),
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
history: Vec<History>,
}
impl Interpreter {
pub fn new() -> Self {
let instructions: VecDeque<String> = VecDeque::new();
let stack: Vec<i32> = Vec::new();
let history: Vec<History> = Vec::new();
Self{
instructions,
stack,
history,
}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for &instruction in instructions {
self.instructions.push_back(instruction.trim().to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
self.instructions.front_mut()
}
fn push_comand (&mut self, val:&str ) -> Result<(), RuntimeError>
{
match val.parse::<i32>() {
Ok(val) => {
self.stack.push(val);
Ok(())
}
Err(_) => Err(RuntimeError::InvalidCommand)
}
}
fn pop_comand (&mut self ) -> Result<i32, RuntimeError>
{
match self.stack.pop() {
Some(val) => Ok(val),
None => Err(RuntimeError::StackUnderflow)
}
}
fn add_comand (&mut self ) -> Result<(i32, i32), RuntimeError>
{
let x =match self.stack.pop() {
Some(val) => val,
None => return Err(RuntimeError::StackUnderflow)
};
let y =match self.stack.pop() {
Some(val) => val,
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow)
}
};
self.stack.push(x+y);
Ok((x,y))
}
fn sub_comand (&mut self ) -> Result<(i32, i32), RuntimeError>
{
let x =match self.stack.pop() {
Some(val) => val,
None => return Err(RuntimeError::StackUnderflow)
};
let y =match self.stack.pop() {
Some(val) => val,
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow)
}
};
self.stack.push(x-y);
Ok((x, y))
}
fn mul_comand (&mut self ) -> Result<(i32, i32), RuntimeError>
{
let x =match self.stack.pop() {
Some(val) => val,
None => return Err(RuntimeError::StackUnderflow)
};
let y =match self.stack.pop() {
Some(val) => val,
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow)
}
};
self.stack.push(x*y);
Ok((x, y))
}
fn div_comand (&mut self ) -> Result<(i32, i32), RuntimeError>
{
let x =match self.stack.pop() {
Some(val) => val,
None => return Err(RuntimeError::StackUnderflow)
};
let y = match self.stack.pop() {
Some(val) if val != 0 => val,
Some(val) if val == 0 =>{
self.stack.push(x);
return Err(RuntimeError::DivideByZero)
},
None => {
self.stack.push(x);
return Err(RuntimeError::StackUnderflow)
},
Some(_)=>unreachable!()
};
self.stack.push(x/y);
Ok((x, y))
}
///интерпретирай следващата команда
pub fn forward(&mut self) -> Result<(), RuntimeError>
{
let mut instruction = match self.instructions.pop_front() {
Some(inst) => inst,
None => return Err(RuntimeError::NoInstructions),
};
instruction = instruction.trim().to_uppercase();
if let Some(index) = instruction.find(char::is_whitespace) {
let (str_comand, str_param) =instruction.split_at(index);
if str_comand.trim() == "PUSH" {
match self.push_comand(str_param.trim()) {
Ok(_) =>{
self.history.push(History::Push());
return Ok(())
},
Err(e)=>{
self.instructions.push_front(instruction);
return Err(e)
}
}
}
else{
self.instructions.push_front(instruction);
return Err(RuntimeError::InvalidCommand)
}
}
else{
if instruction == "ADD" {
match self.add_comand() {
Ok(vals) =>{
self.history.push(History::Add(vals));
return Ok(())
},
Err(e)=>{
self.instructions.push_front(instruction);
return Err(e)
}
}
}
else if instruction == "MUL" {
match self.mul_comand() {
Ok(vals) =>{
self.history.push(History::Mul(vals));
return Ok(())
},
Err(e)=>{
self.instructions.push_front(instruction);
return Err(e)
}
}
}
else if instruction == "SUB" {
match self.sub_comand() {
Ok(vals) =>{
self.history.push(History::Sub(vals));
return Ok(())
},
Err(e)=>{
self.instructions.push_front(instruction);
return Err(e)
}
}
}
else if instruction == "DIV" {
match self.div_comand() {
Ok(vals) =>{
self.history.push(History::Div(vals));
return Ok(())
},
Err(e)=>{
self.instructions.push_front(instruction);
return Err(e)
}
}
}
else if instruction.trim() == "POP" {
match self.pop_comand() {
Ok(x) =>{
self.history.push(History::Pop(x));
return Ok(())
},
Err(e)=>{
self.instructions.push_front(instruction);
return Err(e)
}
}
}
else{
self.instructions.push_front(instruction);
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),
_ => (),
}
}
}
/// "Обръща" последно-изпълнената инструкция с `.forward()`. Това може да се изпълнява отново и
/// отново за всяка инструкция, изпълнена с `.forward()` -- тоест, не пазим само последната
/// инструкция, а списък/стек от всичките досега.
///
/// Ако няма инструкция за връщане, очакваме `RuntimeError::NoInstructions`.
///
pub fn back(&mut self) -> Result<(), RuntimeError> {
match self.history.pop(){
Some(comand) => {
match comand {
History::Push() => {
let val =self.stack.pop().unwrap().to_string();
let mut com: String = "PUSH ".to_string();
com.push_str(val.as_str());
self.instructions.push_front(com);
}
History::Pop(x) => {
self.instructions.push_front("POP".to_string());
self.stack.push(x);
}
History::Add((x,y)) => {
self.stack.pop().unwrap();
self.stack.push(y);
self.stack.push(x);
self.instructions.push_front("ADD".to_string());
}
History::Mul((x,y)) => {
self.stack.pop().unwrap();
self.stack.push(y);
self.stack.push(x);
self.instructions.push_front("MUL".to_string());
}
History::Sub((x,y)) => {
self.stack.pop().unwrap();
self.stack.push(y);
self.stack.push(x);
self.instructions.push_front("SUB".to_string());
}
History::Div((x,y)) => {
self.stack.pop().unwrap();
self.stack.push(y);
self.stack.push(x);
self.instructions.push_front("DIV".to_string());
}
}
Ok(())
},
None =>Err(RuntimeError::NoInstructions)
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20210120-1538662-13cjn27/solution)
warning: unused imports: `process::Command`, `vec`
 --> src/lib.rs:9:34
  |
9 | use std::{collections::VecDeque, process::Command, vec};
  |                                  ^^^^^^^^^^^^^^^^  ^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: 1 warning emitted

    Finished test [unoptimized + debuginfo] target(s) in 2.74s
     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 ... FAILED
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_instructions_after_error stdout ----
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:266:51
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    solution_test::test_instructions_after_error

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 коментара)

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