miy_rpn_calc/
lib.rs

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