rpn_calc_karin/
lib.rs

1// ドキュメントを記述 --- (*1)
2//! # RPN Calc
3//! Reverse Polish notation (RPN) Calc.
4//! # Example
5//! ```
6//! let src = String::from("1 2 + 3 * ");
7//! let a = rpn_calc_karin::eval(src).unwrap();
8//! println!("{}", a); // →9
9//! ```
10
11/// RPN式を計算する関数
12pub fn eval(src: String) -> Result<f64, String> {
13    // 空白でトークンを区切る
14    let tokens = src.split_whitespace();
15    let mut stack: Vec<f64> = vec![];
16    // 繰り返し要素を計算 --- (*2)
17    for tok in tokens {
18        let t = tok.trim();
19        if t == "" {
20            continue;
21        }
22        // 数値ならスタックにPUSH
23        match t.parse::<f64>() {
24            Ok(v) => {
25                stack.push(v);
26                continue;
27            }
28            Err(_) => 0.0,
29        };
30        // 演算子なら2回POPして計算結果をPUSH
31        let b = stack.pop().unwrap_or(0.0);
32        let a = stack.pop().unwrap_or(0.0);
33        match t {
34            "+" => stack.push(a + b),
35            "-" => stack.push(a - b),
36            "*" => stack.push(a * b),
37            "/" => stack.push(a / b),
38            "%" => stack.push(a % b),
39            _ => return Err(format!("invalid operator: {}", t)),
40        }
41    }
42    // 結果を返す --- (*3)
43    if stack.len() == 0 {
44        return Err(format!("no result"));
45    }
46    if stack.len() > 1 {
47        return Err(format!("too many value in stack"));
48    }
49    Ok(stack.pop().unwrap_or(0.0))
50}
51
52/// より手軽に使う
53pub fn eval_str(src: &str) -> String {
54    match eval(String::from(src)) {
55        Ok(v) => format!("{}", v),
56        Err(e) => format!("[ERROR] {}", e),
57    }
58}
59
60// ライブラリを利用するテストを記述 --- (*4)
61#[cfg(test)]
62mod tests {
63    use super::*;
64    #[test]
65    fn it_works() {
66        // eval を使う
67        assert_eq!(eval("1 3 +".to_string()), Ok(4.0));
68        assert_eq!(eval("2 3 *".to_string()), Ok(6.0));
69        assert_eq!(eval("6 3 /".to_string()), Ok(2.0));
70        assert_eq!(eval("6 3 - 1 -".to_string()), Ok(2.0));
71        // eval_str を使う
72        assert_eq!(eval_str("1 2 3 + +"), "6".to_string());
73        assert_eq!(eval_str("1 2 3 * +"), "7".to_string());
74    }
75}