Решение на Reversible Interpreter от Богомила Петрова
Към профила на Богомила Петрова
Резултати
- 15 точки от тестове
- 0 бонус точки
- 15 точки общо
- 12 успешни тест(а)
- 0 неуспешни тест(а)
Код
use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
InvalidCommand,
NoInstructions,
}
#[derive(Debug, Default)]
pub struct Interpreter {
pub instructions: VecDeque<String>,
pub stack: Vec<i32>,
pub backtrace: Vec<Vec<String>>,
pub instruction_back: Vec<String>,
}
impl Interpreter {
pub fn new() -> Self {
let instr: VecDeque<String> = VecDeque::new();
let stack = Vec::new();
let backtrace: Vec<Vec<String>> = Vec::new();
let back: Vec<String> = Vec::new();
Interpreter {instructions: instr, stack: stack, backtrace: backtrace, instruction_back: back}
}
pub fn add_instructions(&mut self, instructions: &[&str]) {
for i in instructions
{
self.instructions.push_back(i.to_string());
}
}
pub fn current_instruction(&mut self) -> Option<&mut String> {
if let Some(elem) = self.instructions.get_mut(0) {
return Some(elem);
}
else
{
return None
}
}
pub fn forward(&mut self) -> Result<(), RuntimeError> {
let elem = self.instructions.get_mut(0);
if elem == None
{
return Err(RuntimeError::NoInstructions)
}
let mut command_split = elem.unwrap().split_whitespace();
let command_name = command_split.next().unwrap();
if command_name == "PUSH"
{
let second_param = command_split.next();
let s = command_split.next();
if second_param == None || s != None
{
return Err(RuntimeError::InvalidCommand)
}
let my_int = second_param.unwrap().parse::<i32>().unwrap();
self.stack.push(my_int);
let mut instr = Vec::new();
instr.push("POP".to_string());
self.backtrace.push(instr);
()
} else if command_name == "POP"
{
let second_param = command_split.next();
if second_param != None
{
return Err(RuntimeError::InvalidCommand)
}
if self.stack.len() == 0
{
return Err(RuntimeError::StackUnderflow)
}
let old_num = self.stack.pop();
let word1 = "PUSH ".to_string();
let word2 = old_num.unwrap().to_string();
let fin_word = word1 + &word2;
let mut instr = Vec::new();
instr.push(fin_word);
self.backtrace.push(instr);
()
} else if command_name == "ADD"
{
let second_param = command_split.next();
if second_param != None
{
return Err(RuntimeError::InvalidCommand)
}
if self.stack.len() < 2
{
return Err(RuntimeError::StackUnderflow)
}
let first_num = self.stack.pop().unwrap();
let second_num = self.stack.pop().unwrap();
self.stack.push(first_num+second_num);
let word2 = second_num.to_string();
let word3 = first_num.to_string();
let first_command = "PUSH ".to_string() + &word2;
let second_command = "PUSH ".to_string() + &word3;
let mut instr = Vec::new();
instr.push("POP".to_string());
instr.push(first_command);
instr.push(second_command);
self.backtrace.push(instr);
()
} else if command_name == "MUL"
{
let second_param = command_split.next();
if second_param != None
{
return Err(RuntimeError::InvalidCommand)
}
if self.stack.len() < 2
{
return Err(RuntimeError::StackUnderflow)
}
let first_num = self.stack.pop().unwrap();
let second_num = self.stack.pop().unwrap();
self.stack.push(first_num*second_num);
let word2 = second_num.to_string();
let word3 = first_num.to_string();
let first_command = "PUSH ".to_string() + &word2;
let second_command = "PUSH ".to_string() + &word3;
let mut instr = Vec::new();
instr.push("POP".to_string());
instr.push(first_command);
instr.push(second_command);
self.backtrace.push(instr);
()
} else if command_name == "SUB"
{
let second_param = command_split.next();
if second_param != None
{
return Err(RuntimeError::InvalidCommand)
}
if self.stack.len() < 2
{
return Err(RuntimeError::StackUnderflow)
}
let first_num = self.stack.pop().unwrap();
let second_num = self.stack.pop().unwrap();
self.stack.push(first_num-second_num);
let word2 = second_num.to_string();
let word3 = first_num.to_string();
let first_command = "PUSH ".to_string() + &word2;
let second_command = "PUSH ".to_string() + &word3;
let mut instr = Vec::new();
instr.push("POP".to_string());
instr.push(first_command);
instr.push(second_command);
self.backtrace.push(instr);
()
} else if command_name == "DIV"
{
let second_param = command_split.next();
if second_param != None
{
return Err(RuntimeError::InvalidCommand)
}
if self.stack.len() < 2
{
return Err(RuntimeError::StackUnderflow)
}
let first_num = self.stack.pop().unwrap();
let second_num = self.stack.pop().unwrap();
if second_num == 0
{
self.stack.push(second_num);
self.stack.push(first_num);
return Err(RuntimeError::DivideByZero)
}
self.stack.push(first_num/second_num);
let word2 = second_num.to_string();
let word3 = first_num.to_string();
let first_command = "PUSH ".to_string() + &word2;
let second_command = "PUSH ".to_string() + &word3;
let mut instr = Vec::new();
instr.push("POP".to_string());
instr.push(first_command);
instr.push(second_command);
self.backtrace.push(instr);
()
} else
{
return Err(RuntimeError::InvalidCommand)
}
self.instruction_back.push(self.instructions.get_mut(0).unwrap().to_string());
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 elem = self.backtrace.pop();
if elem == None
{
return Err(RuntimeError::NoInstructions)
}
for instruction in elem.unwrap() {
let mut command_split = instruction.split_whitespace();
let command_name = command_split.next().unwrap();
if command_name == "PUSH"
{
let second_param = command_split.next();
let s = command_split.next();
if second_param == None || s != None
{
return Err(RuntimeError::InvalidCommand)
}
let my_int = second_param.unwrap().parse::<i32>().unwrap();
self.stack.push(my_int);
()
} else if command_name == "POP"
{
let second_param = command_split.next();
if second_param != None
{
return Err(RuntimeError::InvalidCommand)
}
if self.stack.len() == 0
{
return Err(RuntimeError::StackUnderflow)
}
self.stack.pop();
()
}
}
self.instructions.push_front(self.instruction_back.pop().unwrap());
Ok(())
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20210120-1538662-o5x4mk/solution) 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 ... 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