Решение на Forth от Андрей

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

Към профила на Андрей

Резултати

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

Код

use std::collections::HashMap;
use std::fmt::{self, Debug};
#[derive(Debug, Default)]
pub struct Interpreter {
stack: Vec<i32>,
defs: HashMap<String, Def>,
}
impl Interpreter {
pub fn new() -> Self {
Self::default()
}
pub fn def_var(&mut self, name: &str, val: i32) {
self.defs.insert(name.to_string(), Def::Var(val));
}
pub fn def_unary_op<F>(&mut self, name: &str, op: F)
where
F: Fn(i32) -> i32 + 'static,
{
self.defs
.insert(name.to_string(), Def::UnaryOp(Box::new(op)));
}
pub fn def_binary_op<F>(&mut self, name: &str, op: F)
where
F: Fn(i32, i32) -> i32 + 'static,
{
self.defs
.insert(name.to_string(), Def::BinaryOp(Box::new(op)));
}
/// Изпълнява програмата `input` в този интерпретатор.
///
/// Ако програмата се изпълни успрешно се връща `Ok(top)`, където
/// `top` е елемента на върха на стека, или `None` ако стекът е празен.
///
/// Ако по време на изпълнението се срещне грешка се връща `Err`.
///
pub fn run(&mut self, input: &str) -> Result<Option<i32>, RuntimeError> {
input
.split_whitespace()
.filter(|&word| word != "")
.fold(Ok(()), |err, word| match err {
Ok(_) => self.eval_word(word),
Err(err) => Err(err),
})?;
Ok(self.stack.last().cloned())
}
pub fn stack<'a>(&'a self) -> impl Iterator<Item = i32> + 'a {
self.stack.iter().rev().cloned()
}
fn eval_word(&mut self, word: &str) -> Result<(), RuntimeError> {
match word {
"ADD" => self.eval_binary_op(|x, y| x + y)?,
"SUB" => self.eval_binary_op(|x, y| x - y)?,
"MUL" => self.eval_binary_op(|x, y| x * y)?,
"DIV" => {
let arg1 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
let arg2 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
if arg2 == 0 {
return Err(RuntimeError::DivideByZero);
}
let res = arg1 / arg2;
self.stack.push(res);
},
"DUP" => {
let arg1 = *self.stack.last().ok_or(RuntimeError::StackUnderflow)?;
self.stack.push(arg1);
},
"SWAP" => {
let top = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
let bottom = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.push(top);
self.stack.push(bottom);
},
"POP" => {
self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
},
_ => match word.parse::<i32>() {
Ok(n) => self.stack.push(n),
Err(_) => match self.defs.get_mut(word) {
Some(Def::Var(v)) => {
self.stack.push(*v);
},
Some(Def::UnaryOp(op)) => {
let arg1 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.push(op(arg1));
},
Some(Def::BinaryOp(op)) => {
let arg1 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
let arg2 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.push(op(arg1, arg2));
},
None => Err(RuntimeError::UnknownWord)?,
}
}
};
Ok(())
}
fn eval_binary_op(&mut self, op: impl Fn(i32, i32) -> i32) -> Result<(), RuntimeError> {
let arg1 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
let arg2 = self.stack.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.push(op(arg1, arg2));
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RuntimeError {
DivideByZero,
StackUnderflow,
UnknownWord,
}
enum Def {
Var(i32),
UnaryOp(Box<FnMut(i32) -> i32>),
BinaryOp(Box<FnMut(i32, i32) -> i32>),
}
impl Debug for Def {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Def::Var(v) => f.debug_tuple("Def::Val").field(v).finish(),
Def::UnaryOp(_) => f.debug_tuple("Def::UnaryOp").field(&"_").finish(),
Def::BinaryOp(_) => f.debug_tuple("Def::BinaryOp").field(&"_").finish(),
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20190128-22631-v0g8rt/solution)
    Finished dev [unoptimized + debuginfo] target(s) in 7.11s
     Running target/debug/deps/solution-2e785d603b538f71

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-29808948fb50ed3a

running 10 tests
test solution_test::test_builtin_arithmetic ... ok
test solution_test::test_builtin_dup ... ok
test solution_test::test_builtin_pop ... ok
test solution_test::test_builtin_swap ... ok
test solution_test::test_def_binary ... ok
test solution_test::test_def_unary ... ok
test solution_test::test_def_var ... ok
test solution_test::test_multiple_run ... ok
test solution_test::test_unknown_word ... ok
test solution_test::test_whitespace ... ok

test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests solution

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

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

Андрей качи първо решение на 14.01.2019 03:25 (преди над 6 години)