Решение на 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 Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
current: String,
history: Vec<String>,
buffered: VecDeque<String>
// + още полета за поддръжка на .back() метода
}
impl Interpreter {
/// Конструира нов интерпретатор с празен стек и никакви инструкции.
pub fn new() -> Self {
return Interpreter{ instructions: VecDeque::new() , stack: Vec::new(), current: String::new(), history : Vec::new(), buffered: VecDeque::new()};
}
/// Добавя инструкции от дадения списък към края на `instructions`. Примерно:
///
/// interpreter.add_instructions(&[
/// "PUSH 1",
/// "PUSH 2",
/// "ADD",
/// ]);
///
/// Инструкциите не се интерпретират, само се записват.
///
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instruction in instructions {
self.instructions.push_back(instruction.to_string());
}
}
pub fn run_history(&mut self) -> Result<(), RuntimeError> {
self.stack = Vec::new();
loop {
match self.forward() {
Err(RuntimeError::NoInstructions) => return Ok(()),
Err(e) => return Err(e),
_ => (),
}
}
}
/// Връща mutable reference към инструкцията, която ще се изпълни при
/// следващия `.forward()` -- първата в списъка/дека.
///
pub fn current_instruction(&mut self) -> Option<&mut String> {
let res = self.instructions.get_mut(0);
if res == None {
return None;
}
return Some(res.unwrap());
}
/// Интерпретира първата инструкция в `self.instructions` по правилата описани по-горе. Записва
/// някаква информация за да може успешно да се изпълни `.back()` в по-нататъшен момент.
///
/// Ако няма инструкции, връща `RuntimeError::NoInstructions`. Другите грешки идват от
/// обясненията по-горе.
///
pub fn forward(&mut self) -> Result<(), RuntimeError> {
if self.instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let line = self.instructions.pop_front();
if line == None {
return Err(RuntimeError::NoInstructions);
}
let unwrapped = line.unwrap();
let tokens_split = unwrapped.split(' ');
let tokens = tokens_split.collect::<Vec<&str>>();
//let parameters = 0;
let mut result = 0;
let mut err = Ok(());
if tokens.len() > 2 {
return Err(RuntimeError::InvalidCommand);
}
let mut returns : Vec<i32> = Vec::new();
//print!("{:?}\n", tokens);
let mut isPop = false;
for (pos, token) in tokens.iter().enumerate() {
if pos == 0 {
match token {
&"PUSH" => {
if tokens.len() != 2 {
err = Err(RuntimeError::InvalidCommand);
break;
}
},
&"POP" => {
let current = self.stack.pop();
isPop = true;
if current == None {
err = Err(RuntimeError::StackUnderflow);
break;
}
result = current.unwrap();
returns.push(result);
},
&_ => {
if self.stack.len() < 2 {
err = Err(RuntimeError::StackUnderflow);
break;
}
let x = self.stack.pop();
let y = self.stack.pop();
returns.push(x.unwrap());
returns.push(y.unwrap());
match token {
&"ADD" => {
result = x.unwrap() + y.unwrap();
//print!("\n{:?}, {:?}\n", x.unwrap(), y.unwrap());
},
&"MUL" => {
result = x.unwrap() * y.unwrap();
},
&"SUB"=> {
result = x.unwrap() - y.unwrap();
}
&"DIV" => {
if y.unwrap() == 0 {
err = Err(RuntimeError::DivideByZero);
break;
}
result = x.unwrap() / y.unwrap();
},
&_ => {
err = Err(RuntimeError::InvalidCommand);
break;
}
}
}
}
} else {
let number = token.parse::<i32>();
match number {
Err(_e) => {
err = Err(RuntimeError::InvalidCommand);
},
Ok(val) => {
//print!("{:?}\n", val);
result = val;
}
}
}
}
match err {
Err(e) => {
for x in returns.iter().rev() {
self.stack.push(*x);
}
self.instructions.push_back(unwrapped);
return Err(e);
}
Ok(_) => {
//print!("RESULT: \n{:?}\n", result);
self.history.push(unwrapped);
if isPop {
return Ok(());
}
self.stack.push(result);
return Ok(());
}
}
}
/// Вика `.forward()` докато не свършат инструкциите (може и да се имплементира по други
/// начини, разбира се) или има грешка.
///
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> {
let his = self.history.pop();
let mut buffer = VecDeque::new();
buffer = self.instructions.clone();
self.instructions = VecDeque::new();
loop {
let mut ins = self.history.pop();
if ins == None {
break;
}
self.instructions.push_front(ins.unwrap());
}
self.stack = Vec::new();
self.run();
self.instructions = buffer;
if his == None {
return Err(RuntimeError::NoInstructions);
}
self.instructions.push_front(his.unwrap());
Ok(())
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-1d3a79j/solution) warning: value assigned to `buffer` is never read --> src/lib.rs:225:13 | 225 | let mut buffer = VecDeque::new(); | ^^^^^^^^^^ | = note: `#[warn(unused_assignments)]` on by default = help: maybe it is overwritten before being read? warning: variable does not need to be mutable --> src/lib.rs:232:17 | 232 | let mut ins = self.history.pop(); | ----^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable `isPop` should have a snake case name --> src/lib.rs:105:18 | 105 | let mut isPop = false; | ^^^^^ help: convert the identifier to snake case: `is_pop` | = note: `#[warn(non_snake_case)]` on by default warning: unused `std::result::Result` that must be used --> src/lib.rs:242:9 | 242 | self.run(); | ^^^^^^^^^^^ | = note: `#[warn(unused_must_use)]` on by default = note: this `Result` may be an `Err` variant, which should be handled warning: 4 warnings emitted 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 ... 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 ... 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 ... 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: `Err(StackUnderflow)`, right: `Err(InvalidCommand)`: Should have been invalid: ADD 42', tests/solution_test.rs:242:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ---- solution_test::test_instructions_after_error stdout ---- thread 'main' panicked at 'assertion failed: `(left == right)` left: `["PUSH 3", "DIV"]`, right: `["DIV", "PUSH 3"]`', tests/solution_test.rs:215: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: POSH', tests/solution_test.rs:265:9 failures: solution_test::test_arg_number solution_test::test_instructions_after_error 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'
История (2 версии и 0 коментара)
Владислав качи решение на 19.01.2021 15:40 (преди над 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>,
current: String,
history: Vec<String>,
buffered: VecDeque<String>
// + още полета за поддръжка на .back() метода
}
impl Interpreter {
/// Конструира нов интерпретатор с празен стек и никакви инструкции.
pub fn new() -> Self {
return Interpreter{ instructions: VecDeque::new() , stack: Vec::new(), current: String::new(), history : Vec::new(), buffered: VecDeque::new()};
}
/// Добавя инструкции от дадения списък към края на `instructions`. Примерно:
///
/// interpreter.add_instructions(&[
/// "PUSH 1",
/// "PUSH 2",
/// "ADD",
/// ]);
///
/// Инструкциите не се интерпретират, само се записват.
///
pub fn add_instructions(&mut self, instructions: &[&str]) {
for instruction in instructions {
self.instructions.push_back(instruction.to_string());
}
}
pub fn run_history(&mut self) -> Result<(), RuntimeError> {
self.stack = Vec::new();
loop {
match self.forward() {
Err(RuntimeError::NoInstructions) => return Ok(()),
Err(e) => return Err(e),
_ => (),
}
}
}
/// Връща mutable reference към инструкцията, която ще се изпълни при
/// следващия `.forward()` -- първата в списъка/дека.
///
pub fn current_instruction(&mut self) -> Option<&mut String> {
let res = self.instructions.get_mut(0);
if res == None {
return None;
}
return Some(res.unwrap());
}
/// Интерпретира първата инструкция в `self.instructions` по правилата описани по-горе. Записва
/// някаква информация за да може успешно да се изпълни `.back()` в по-нататъшен момент.
///
/// Ако няма инструкции, връща `RuntimeError::NoInstructions`. Другите грешки идват от
/// обясненията по-горе.
///
pub fn forward(&mut self) -> Result<(), RuntimeError> {
if self.instructions.len() == 0 {
return Err(RuntimeError::NoInstructions);
}
let line = self.instructions.pop_front();
if line == None {
return Err(RuntimeError::NoInstructions);
}
let unwrapped = line.unwrap();
let tokens_split = unwrapped.split(' ');
let tokens = tokens_split.collect::<Vec<&str>>();
//let parameters = 0;
let mut result = 0;
let mut err = Ok(());
if tokens.len() > 2 {
return Err(RuntimeError::InvalidCommand);
}
+ let mut returns : Vec<i32> = Vec::new();
+
//print!("{:?}\n", tokens);
+ let mut isPop = false;
for (pos, token) in tokens.iter().enumerate() {
if pos == 0 {
match token {
&"PUSH" => {
if tokens.len() != 2 {
err = Err(RuntimeError::InvalidCommand);
break;
}
},
&"POP" => {
let current = self.stack.pop();
-
+ isPop = true;
if current == None {
err = Err(RuntimeError::StackUnderflow);
break;
}
result = current.unwrap();
+
+ returns.push(result);
},
&_ => {
if self.stack.len() < 2 {
err = Err(RuntimeError::StackUnderflow);
break;
}
let x = self.stack.pop();
let y = self.stack.pop();
+ returns.push(x.unwrap());
+ returns.push(y.unwrap());
match token {
&"ADD" => {
result = x.unwrap() + y.unwrap();
//print!("\n{:?}, {:?}\n", x.unwrap(), y.unwrap());
},
&"MUL" => {
result = x.unwrap() * y.unwrap();
},
&"SUB"=> {
result = x.unwrap() - y.unwrap();
}
&"DIV" => {
if y.unwrap() == 0 {
err = Err(RuntimeError::DivideByZero);
break;
}
result = x.unwrap() / y.unwrap();
},
&_ => {
err = Err(RuntimeError::InvalidCommand);
break;
}
}
}
}
} else {
let number = token.parse::<i32>();
match number {
Err(_e) => {
err = Err(RuntimeError::InvalidCommand);
},
Ok(val) => {
//print!("{:?}\n", val);
result = val;
}
}
}
}
match err {
Err(e) => {
+ for x in returns.iter().rev() {
+ self.stack.push(*x);
+ }
self.instructions.push_back(unwrapped);
return Err(e);
}
Ok(_) => {
//print!("RESULT: \n{:?}\n", result);
- self.stack.push(result);
self.history.push(unwrapped);
+
+ if isPop {
+ return Ok(());
+ }
+
+ self.stack.push(result);
return Ok(());
}
}
}
/// Вика `.forward()` докато не свършат инструкциите (може и да се имплементира по други
/// начини, разбира се) или има грешка.
///
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> {
let his = self.history.pop();
let mut buffer = VecDeque::new();
buffer = self.instructions.clone();
self.instructions = VecDeque::new();
loop {
let mut ins = self.history.pop();
if ins == None {
break;
}
self.instructions.push_front(ins.unwrap());
}
self.stack = Vec::new();
self.run();
self.instructions = buffer;
if his == None {
return Err(RuntimeError::NoInstructions);
}
self.instructions.push_front(his.unwrap());
Ok(())
}
}